Can someone explain this base conversion code - javascript

var ShortURL = new function() {
var _alphabet = '23456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ-_',
_base = _alphabet.length;
this.encode = function(num) {
var str = '';
while (num > 0) {
str = _alphabet.charAt(num % _base) + str;
num = Math.floor(num / _base);
}
return str;
};
this.decode = function(str) {
var num = 0;
for (var i = 0; i < str.length; i++) {
num = num * _base + _alphabet.indexOf(str.charAt(i));
}
return num;
};
};
I understand encode works by converting from decimal to custom base (custom alphabet/numbers in this case)
I am not quite sure how decode works.
Why do we multiply base by a current number and then add the position number of the alphabet? I know that to convert 010 base 2 to decimal, we would do
(2 * 0^2) + (2 * 1^1) + (2 * 0 ^ 0) = 2
Not sure how it is represented in that decode algorithm
EDIT:
My own decode version
this.decode2 = function (str) {
var result = 0;
var position = str.length - 1;
var value;
for (var i = 0; i < str.length; i++) {
value = _alphabet.indexOf(str[i]);
result += value * Math.pow(_base, position--);
}
return result;
}
This is how I wrote my own decode version (Just like I want convert this on paper. I would like someone to explain more in detail how the first version of decode works. Still don't get why we multiply num * base and start num with 0.

OK, so what does 376 mean as a base-10 output of your encode() function? It means:
1 * 100 +
5 * 10 +
4 * 1
Why? Because in encode(), you divide by the base on every iteration. That means that, implicitly, the characters pushed onto the string on the earlier iterations gain in significance by a factor of the base each time through the loop.
The decode() function, therefore, multiplies by the base each time it sees a new character. That way, the first digit is multiplied by the base once for every digit position past the first that it represents, and so on for the rest of the digits.
Note that in the explanation above, the 1, 5, and 4 come from the positions of the characters 3, 7, and 6 in the "alphabet" list. That's how your encoding/decoding mechanism works. If you feed your decode() function a numeric string encoded by something trying to produce normal base-10 numbers, then of course you'll get a weird result; that's probably obvious.
edit To further elaborate on the decode() function: forget (for now) about the special base and encoding alphabet. The process is basically the same regardless of the base involved. So, let's look at a function that interprets a base-10 string of numeric digits as a number:
function decode10(str) {
var num = 0, zero = '0'.charCodeAt(0);
for (var i = 0; i < str.length; ++i) {
num = (num * 10) + (str[i] - zero);
}
return num;
}
The accumulator variable num is initialized to 0 first, because before examining any characters of the input numeric string the only value that makes sense to start with is 0.
The function then iterates through each character of the input string from left to right. On each iteration, the accumulator is multiplied by the base, and the digit value at the current string position is added.
If the input string is "214", then, the iteration will proceed as follows:
num is set to 0
First iteration: str[i] is 2, so (num * 10) + 2 is 2
Second iteration: str[i] is 1, so (num * 10) + 1 is 21
Third iteration: str[i] is 4, so (num * 10) + 4 is 214
The successive multiplications by 10 achieve what the call to Math.pow() does in your code. Note that 2 is multiplied by 10 twice, which effectively multiplies it by 100.
The decode() routine in your original code does the same thing, only instead of a simple character code computation to get the numeric value of a digit, it performs a lookup in the alphabet string.

Both the original and your own version of the decode function achieve the same thing, but the original version does it more efficiently.
In the following assignment:
num = num * _base + _alphabet.indexOf(str.charAt(i));
... there are two parts:
_alphabet.indexOf(str.charAt(i))
The indexOf returns the value of a digit in base _base. You have this part in your own algorithm, so that should be clear.
num * _base
This multiplies the so-far accumulated result. The rest of my answer is about that part:
In the first iteration this has no effect, as num is still 0 at that point. But at the end of the first iteration, num contains the value as if the str only had its left most character. It is the base-51 digit value of the left most digit.
From the next iteration onwards, the result is multiplied by the base, which makes room for the next value to be added to it. It functions like a digit shift.
Take this example input to decode:
bd35
The individual characters represent value 8, 10, 1 and 3. As there are 51 characters in the alphabet, we're in base 51. So bd35 this represents value:
8*51³ + 10*51² + 1*51 + 3
Here is a table with the value of num after each iteration:
8
8*51 + 10
8*51² + 10*51 + 1
8*51³ + 10*51² + 1*51 + 3
Just to make the visualisation cleaner, let's put the power of 51 in a column header, and remove that from the rows:
3 2 1 0
----------------------------
8
8 10
8 10 1
8 10 1 3
Note how the 8 shifts to the left at each iteration and gets multiplied with the base (51). The same happens with 10, as soon as it is shifted in from the right, and the same with the 1, and 3, although that is the last one and doesn't shift any more.
The multiplication num * _base represents thus a shift of base-digits to the left, making room for a new digit to shift in from the right (through simple addition).
At the last iteration all digits have shifted in their correct position, i.e. they have been multiplied by the base just enough times.
Putting your own algorithm in the same scheme, you'd have this table:
3 2 1 0
----------------------------
8
8 10
8 10 1
8 10 1 3
Here, there is no shifting: the digits are immediately put in the right position, i.e. they are multiplied with the correct power of 51 immediately.

You ask
I would like to understand how the decode function works from logical perspective. Why are we using num * base and starting with num = 0.
and write that
I am not quite sure how decode works. Why do we multiply base by a
current number and then add the position number of the alphabet? I
know that to convert 010 base 2 to decimal, we would do
(2 * 0^2) + (2 * 1^1) + (2 * 0 ^ 0) = 2
The decode function uses an approach to base conversion known as Horner's rule, used because it is computationally efficient:
start with a variable set to 0, num = 0
multiply the variable num by the base
take the value of the most significant digit (the leftmost digit) and add it to num,
repeat step 2 and 3 for as long as there are digits left to convert,
the variable num now contains the converted value (in base 10)
Using an example of a hexadecimal number A5D:
start with a variable set to 0, num = 0
multiply by the base (16), num is now still 0
take the value of the most significant digit (the A has a digit value of 10) and add it to num, num is now 10
repeat step 2, multiply the variable num by the base (16), num is now 160
repeat step 3, add the hexadecimal digit 5 to num, num is now 165
repeat step 2, multiply the variable num by the base (16), num is now 2640
repeat step 3, add the hexadecimal digit D to num (add 13)
there are no digits left to convert, the variable num now contains the converted value (in base 10), which is 2653
Compare the expression of the standard approach:
(10 × 162) + (5 × 161) + (13 × 160) = 2653
to the use of Horner's rule:
(((10 × 16) + 5) × 16) + 13 = 2653
which is exactly the same computation, but rearranged in a form making it easier to compute. This is how the decode function works.
Why are we using num * base and starting with num = 0.
The conversion algorithm needs a start value, therefore num is set to 0. For each repetition (each loop iteration), num is multiplied by base. This only has any effect on the second iteration, but is written like this to make it easier to write the conversion as a for loop.

Related

In JavaScript, is there a way to make 0.84729347293923 into an integer without using any string or regex manipulation?

Given any number between 0 and 1, such as 0.84729347293923, is there a simple way to make it into 84729347293923 without string or regex manipulation? I can think of using a loop, which probably is no worse than using a string because it is O(n) with n being the number of digits. But is there a better way?
function getRandom() {
let r = Math.random();
while (Math.floor(r) !== r) r *= 10;
return r;
}
for (let i = 0; i < 10; i++)
console.log(getRandom());
Integers mod 1 = 0, non integers mod 1 != 0.
while ((r*=10) % 1);
Ok, just want to refactor my code (i realized that was bad so this is what i discovered to correctly get the value as you requested).
NOTE: As the question says that "given any number between 0 and 1", this solution only works for values between 0 and 1:
window.onload = ()=>{
function getLen(num){
let currentNumb = num;
let integratedArray = [];
let realLen = 0;
/*While the number is not an integer, we will multiply the copy of the original
*value by ten, and when the loop detects that the number is already an integer
*the while simply breaks, in this process we are storing each transformations
*of the number in an array called integratedArray*/
while(!(Number.isInteger(currentNumb))){
currentNumb *= 10;
integratedArray.push(currentNumb);
}
/*We iterate over the array and compare each value of the array with an operation
*in which the resultant value should be exactly the same as the actual item of the
*array, in the case that both are equal we assign the var realLen to i, and
*in case that the values were not the same, we simply breaks the loop, if the
*values are not the same, this indicates that we found the "trash numbers", so
*we simply skip them.*/
for(let i = 0; i < integratedArray.length; i++){
if(Math.floor(integratedArray[i]) === Math.floor(num * Math.pow(10, i + 1))){
realLen = i;
}else{
break;
}
}
return realLen;
}
//Get the float value of a number between 0 and 1 as an integer.
function getShiftedNumber(num){
//First we need the length to get the float part of the number as an integer
const len = getLen(num);
/*Once we have the length of the number we simply multiply the number by
*(10) ^ numberLength, this eliminates the comma (,), or point (.), and
*automatically transforms the number to an integer in this case a large integer*/
return num * (Math.pow(10, len));
}
console.log(getShiftedNumber(0.84729347293923));
}
So the explanation is the next:
Because we want to convert this number without using any string, regex or any another thing, first we need to get the length of the number, this is a bit hard to do without using string conversions... so i did the function getLen for this purpose.
In the function getLen, we have 3 variables:
currentNumb: This var is a copy of the original value (the original number), this value help us to found the length of the number and we can do some transforms to this value whitout changing the original reference of the number.
We need to multiply this value any times is needed to transform the number to an integer and then multiplyng this value by ten to ten.
with the help of a while (this method makes the number a false integer).
NOTE: I saw "False integer" because when i was making the tests i realized that in the number is being adding more digits than normal... (Very very strange), so this stupid but important thing makes neccesary the filter of these "trash numbers", so later we proccess them.
integratedArray: This array stores the values of the result of the first while operations, so the last number stored in this array is an integer, but this number is one of the "fake integers", so with this array we need to iterate later to compare what of those stored values are different to the original value multiplied by (10 * i + 1), so here is the hint:
In this case the first 12 values of this array are exactly the same with the operation of Math.floor(num * Math.pow(10, i + 1))), but in the 13th value of the array these values are not the same so... yes!, there are those "trash numbers" that we were searching for.
realLen: This is the variable where we will store the real length of the number converting the float part of this number in an integer.
Some binary search approach:
Its useless if avarage length < 8;
It contains floating point issues.
But hey it is O(log n) with tons of wasted side computations - i guess if one counts them its event worse than just plain multiplication.
I prefer #chiliNUT answer. One line stamp.
function floatToIntBinarySearch(number){
const max_safe_int_length = 16;
const powers = [
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000
]
let currentLength = 16
let step = 16
let _number = number * powers[currentLength]
while(_number % 1 != 0 || (_number % 10 | 0) == 0){
step /= 2
if( (_number % 10 | 0) == 0 && !(_number % 1 != 0)){
currentLength = currentLength - step;
} else {
currentLength = step + currentLength;
}
if(currentLength < 1 || currentLength > max_safe_int_length * 2) throw Error("length is weird: " + currentLength)
_number = number * powers[currentLength]
console.log(currentLength, _number)
if(Number.isNaN(_number)) throw Error("isNaN: " + ((number + "").length - 2) + " maybe greater than 16?")
}
return number * powers[currentLength]
}
let randomPower = 10 ** (Math.random() * 10 | 0)
let test = (Math.random() * randomPower | 0) / randomPower
console.log(test)
console.log(floatToIntBinarySearch(test))

How to Generate a random number of fixed length using JavaScript?

I'm trying to generate a random number that must have a fixed length of exactly 6 digits.
I don't know if JavaScript has given below would ever create a number less than 6 digits?
Math.floor((Math.random()*1000000)+1);
I found this question and answer on StackOverflow here. But, it's unclear.
EDIT: I ran the above code a bunch of times, and Yes, it frequently creates numbers less than 6 digits. Is there a quick/fast way to make sure it's always exactly 6 digits?
console.log(Math.floor(100000 + Math.random() * 900000));
Will always create a number of 6 digits and it ensures the first digit will never be 0. The code in your question will create a number of less than 6 digits.
Only fully reliable answer that offers full randomness, without loss. The other ones prior to this answer all looses out depending on how many characters you want. The more you want, the more they lose randomness.
They achieve it by limiting the amount of numbers possible preceding the fixed length.
So for instance, a random number of fixed length 2 would be 10 - 99. For 3, 100 - 999. For 4, 1000 - 9999. For 5 10000 - 99999 and so on. As can be seen by the pattern, it suggests 10% loss of randomness because numbers prior to that are not possible. Why?
For really large numbers ( 18, 24, 48 ) 10% is still a lot of numbers to loose out on.
function generate(n) {
var add = 1, max = 12 - add; // 12 is the min safe number Math.random() can generate without it starting to pad the end with zeros.
if ( n > max ) {
return generate(max) + generate(n - max);
}
max = Math.pow(10, n+add);
var min = max/10; // Math.pow(10, n) basically
var number = Math.floor( Math.random() * (max - min + 1) ) + min;
return ("" + number).substring(add);
}
The generator allows for ~infinite length without lossy precision and with minimal performance cost.
Example:
generate(2)
"03"
generate(2)
"72"
generate(2)
"20"
generate(3)
"301"
generate(3)
"436"
generate(3)
"015"
As you can see, even the zero are included initially which is an additional 10% loss just that, besides the fact that numbers prior to 10^n are not possible.
That is now a total of 20%.
Also, the other options have an upper limit on how many characters you can actually generate.
Example with cost:
var start = new Date(); var num = generate(1000); console.log('Time: ', new Date() - start, 'ms for', num)
Logs:
Time: 0 ms for 7884381040581542028523049580942716270617684062141718855897876833390671831652069714762698108211737288889182869856548142946579393971303478191296939612816492205372814129483213770914444439430297923875275475120712223308258993696422444618241506074080831777597175223850085606310877065533844577763231043780302367695330451000357920496047212646138908106805663879875404784849990477942580056343258756712280958474020627842245866908290819748829427029211991533809630060693336825924167793796369987750553539230834216505824880709596544701685608502486365633618424746636614437646240783649056696052311741095247677377387232206206230001648953246132624571185908487227730250573902216708727944082363775298758556612347564746106354407311558683595834088577220946790036272364740219788470832285646664462382109714500242379237782088931632873392735450875490295512846026376692233811845787949465417190308589695423418373731970944293954443996348633968914665773009376928939207861596826457540403314327582156399232931348229798533882278769760
More hardcore:
generate(100000).length === 100000 -> true
I would go with this solution:
Math.floor(Math.random() * 899999 + 100000)
More generally, generating a random integer with fixed length can be done using Math.pow:
var randomFixedInteger = function (length) {
return Math.floor(Math.pow(10, length-1) + Math.random() * (Math.pow(10, length) - Math.pow(10, length-1) - 1));
}
To answer the question: randomFixedInteger(6);
You can use the below code to generate a random number that will always be 6 digits:
Math.random().toString().substr(2, 6)
Hope this works for everyone :)
Briefly how this works is Math.random() generates a random number between 0 and 1 which we convert to a string and using .toString() and take a 6 digit sample from said string using .substr() with the parameters 2, 6 to start the sample from the 2nd char and continue it for 6 characters.
This can be used for any length number.
If you want to do more reading on this here are some links to the docs to save you some googling:
Math.random(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
.toString(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
.substr(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr
short with arbitrary precision
below code ALWAYS generate string with n digits - solution in snippet use it
[...Array(n)].map(_=>Math.random()*10|0).join``
let gen = n=> [...Array(n)].map(_=>Math.random()*10|0).join``
// TEST: generate 6 digit number
// first number can't be zero - so we generate it separatley
let sixDigitStr = (1+Math.random()*9|0) + gen(5)
console.log( +(sixDigitStr) ) // + convert to num
100000 + Math.floor(Math.random() * 900000);
will give a number from 100000 to 999999 (inclusive).
Based on link you've provided, right answer should be
Math.floor(Math.random()*899999+100000);
Math.random() returns float between 0 and 1, so minimum number will be 100000, max - 999999. Exactly 6 digits, as you wanted :)
Here is my function I use. n - string length you want to generate
function generateRandomNumber(n) {
return Math.floor(Math.random() * (9 * Math.pow(10, n - 1))) + Math.pow(10, n - 1);
}
This is another random number generator that i use often, it also prevent the first digit from been zero(0)
function randomNumber(length) {
var text = "";
var possible = "123456789";
for (var i = 0; i < length; i++) {
var sup = Math.floor(Math.random() * possible.length);
text += i > 0 && sup == i ? "0" : possible.charAt(sup);
}
return Number(text);
}
let length = 6;
("0".repeat(length) + Math.floor(Math.random() * 10 ** length)).slice(-length);
Math.random() - Returns floating point number between 0 - 1
10 ** length - Multiply it by the length so we can get 1 - 6 length numbers with decimals
Math.floor() - Returns above number to integer(Largest integer to the given number).
What if we get less than 6 digits number?
That's why you have to append 0s with it.
"0".repeat() repeats the given string which is 0
So we may get more than 6 digits right?
That's why we have to use "".slice() method. It returns the array within given indexes. By giving minus values, it counts from the last element.
I created the below function to generate random number of fix length:
function getRandomNum(length) {
var randomNum =
(Math.pow(10,length).toString().slice(length-1) +
Math.floor((Math.random()*Math.pow(10,length))+1).toString()).slice(-length);
return randomNum;
}
This will basically add 0's at the beginning to make the length of the number as required.
npm install --save randomatic
var randomize = require('randomatic');
randomize(pattern, length, options);
Example:
To generate a 10-character randomized string using all available characters:
randomize('*', 10);
//=> 'x2_^-5_T[$'
randomize('Aa0!', 10);
//=> 'LV3u~BSGhw'
a: Lowercase alpha characters (abcdefghijklmnopqrstuvwxyz'
A: Uppercase alpha characters (ABCDEFGHIJKLMNOPQRSTUVWXYZ')
0: Numeric characters (0123456789')
!: Special characters (~!##$%^&()_+-={}[];\',.)
*: All characters (all of the above combined)
?: Custom characters (pass a string of custom characters to the options)
NPM repo
I use randojs to make the randomness simpler and more readable. you can pick a random int between 100000 and 999999 like this with randojs:
console.log(rando(100000, 999999));
<script src="https://randojs.com/1.0.0.js"></script>
const generate = n => String(Math.ceil(Math.random() * 10**n)).padStart(n, '0')
// n being the length of the random number.
Use a parseInt() or Number() on the result if you want an integer.
If you don't want the first integer to be a 0 then you could use padEnd() instead of padStart().
I was thinking about the same today and then go with the solution.
var generateOTP = function(otpLength=6) {
let baseNumber = Math.pow(10, otpLength -1 );
let number = Math.floor(Math.random()*baseNumber);
/*
Check if number have 0 as first digit
*/
if (number < baseNumber) {
number += baseNumber;
}
return number;
};
Let me know if it has any bug. Thanks.
"To Generate Random Number Using JS"
console.log(
Math.floor(Math.random() * 1000000)
);
<!DOCTYPE html>
<html>
<body>
<h2>JavaScript Math.random()</h2>
<p id="demo"></p>
</body>
</html>
You can use this module https://www.npmjs.com/package/uid, it generates variable length unique id
uid(10) => "hbswt489ts"
uid() => "rhvtfnt" Defaults to 7
Or you can have a look at this module https://www.npmjs.com/package/shortid
const shortid = require('shortid');
console.log(shortid.generate());
// PPBqWA9
Hope it works for you :)
var number = Math.floor(Math.random() * 9000000000) + 1000000000;
console.log(number);
This can be simplest way and reliable one.
For the length of 6, recursiveness doesn't matter a lot.
function random(len) {
let result = Math.floor(Math.random() * Math.pow(10, len));
return (result.toString().length < len) ? random(len) : result;
}
console.log(random(6));
In case you also want the first digit to be able to be 0 this is my solution:
const getRange = (size, start = 0) => Array(size).fill(0).map((_, i) => i + start);
const getRandomDigit = () => Math.floor(Math.random() * 10);
const generateVerificationCode = () => getRange(6).map(getRandomDigit).join('');
console.log(generateVerificationCode())
generate a random number that must have a fixed length of exactly 6 digits:
("000000"+Math.floor((Math.random()*1000000)+1)).slice(-6)
Generate a random number that will be 6 digits:
console.log(Math.floor(Math.random() * 900000));
Result = 500229
Generate a random number that will be 4 digits:
console.log(Math.floor(Math.random() * 9000));
Result = 8751
This code provides nearly full randomness:
function generator() {
const ran = () => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0].sort((x, z) => {
ren = Math.random();
if (ren == 0.5) return 0;
return ren > 0.5 ? 1 : -1
})
return Array(6).fill(null).map(x => ran()[(Math.random() * 9).toFixed()]).join('')
}
console.log(generator())
This code provides complete randomness:
function generator() {
const ran1 = () => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0].sort((x, z) => {
ren = Math.random();
if (ren == 0.5) return 0;
return ren > 0.5 ? 1 : -1
})
const ran2 = () => ran1().sort((x, z) => {
ren = Math.random();
if (ren == 0.5) return 0;
return ren > 0.5 ? 1 : -1
})
return Array(6).fill(null).map(x => ran2()[(Math.random() * 9).toFixed()]).join('')
}
console.log(generator())
parseInt(Math.random().toString().slice(2,Math.min(length+2, 18)), 10); // 18 -> due to max digits in Math.random
Update:
This method has few flaws:
- Sometimes the number of digits might be lesser if its left padded with zeroes.

Converting large integer to 8 byte array in JavaScript

I'm trying to convert a large number into an 8 byte array in javascript.
Here is an IMEI that I am passing in: 45035997012373300
var bytes = new Array(7);
for(var k=0;k<8;k++) {
bytes[k] = value & (255);
value = value / 256;
}
This ends up giving the byte array: 48,47,7,44,0,0,160,0. Converted back to a long, the value is 45035997012373296, which is 4 less than the correct value.
Any idea why this is and how I can fix it to serialize into the correct bytes?
Since you are converting from decimal to bytes, dividing by 256 is an operation that is pretty easily simulated by splitting up a number in a string into parts. There are two mathematical rules that we can take advantage of.
The right-most n digits of a decimal number can determine divisibility by 2^n.
10^n will always be divisible by 2^n.
Thus we can take the number and split off the right-most 8 digits to find the remainder (i.e., & 255), divide the right part by 256, and then also divide the left part of the number by 256 separately. The remainder from the left part can be shifted into the right part of the number (the right-most 8 digits) by the formula n*10^8 \ 256 = (q*256+r)*10^8 \ 256 = q*256*10^8\256 + r*10^8\256 = q*10^8 + r*5^8, where \ is integer division and q and r are quotient and remainder, respectively for n \ 256. This yields the following method to do integer division by 256 for strings of up to 23 digits (15 normal JS precision + 8 extra yielded by this method) in length:
function divide256(n)
{
if (n.length <= 8)
{
return (Math.floor(parseInt(n) / 256)).toString();
}
else
{
var top = n.substring(0, n.length - 8);
var bottom = n.substring(n.length - 8);
var topVal = Math.floor(parseInt(top) / 256);
var bottomVal = Math.floor(parseInt(bottom) / 256);
var rem = (100000000 / 256) * (parseInt(top) % 256);
bottomVal += rem;
topVal += Math.floor(bottomVal / 100000000); // shift back possible carry
bottomVal %= 100000000;
if (topVal == 0) return bottomVal.toString();
else return topVal.toString() + bottomVal.toString();
}
}
Technically this could be implemented to divide an integer of any arbitrary size by 256, simply by recursively breaking the number into 8-digit parts and handling the division of each part separately using the same method.
Here is a working implementation that calculates the correct byte array for your example number (45035997012373300): http://jsfiddle.net/kkX2U/.
[52, 47, 7, 44, 0, 0, 160, 0]
Your value and the largest JavaScript integer compared:
45035997012373300 // Yours
9007199254740992 // JavaScript's biggest integer
JavaScript cannot represent your original value exactly as an integer; that's why your script breaking it down gives you an inexact representation.
Related:
var diff = 45035997012373300 - 45035997012373298;
// 0 (not 2)
Edit: If you can express your number as a hexadecimal string:
function bytesFromHex(str,pad){
if (str.length%2) str="0"+str;
var bytes = str.match(/../g).map(function(s){
return parseInt(s,16);
});
if (pad) for (var i=bytes.length;i<pad;++i) bytes.unshift(0);
return bytes;
}
var imei = "a000002c072f34";
var bytes = bytesFromHex(imei,8);
// [0,160,0,0,44,7,47,52]
If you need the bytes ordered from least-to-most significant, throw a .reverse() on the result.
store the imei as a hex string (if you can), then parse the string in that manner, this way you can keep the precision when you build the array. I will be back with a PoC when i get home on my regular computer, if this question has not been answered.
something like:
function parseHexString(str){
for (var i=0, j=0; i<str.length; i+=2, j++){
array[j] = parseInt("0x"+str.substr(i, 2));
}
}
or close to that whatever...

Javascript Brainteaser - Reverse Number Determining

Lets say I have a list of numbers in the following form(Ignore the | they are there for formating help).
00|00|xx
00|xx|00
xx|00|00
etc.
Rules: XX can be any number between 1 and 50. No XX values can be identical.
Now I select a random set of numbers(no duplicates) from a list qualifying the above format, and randomly add and subtract them. For example
000011 - 002400 - 230000 = -232389
How can I determine the original numbers and if they were added or subtracted solely from -232389? I'm stumped.
Thanks!
EDIT:
I was looking for a function so I ended up having to make one. Its just a proof of concept function so variables names are ugly http://jsfiddle.net/jPW8A/.
There are bugs in the following implementation, and it fails to work in a dozen of scenarios. Check the selected answer below.
function reverse_add_subtract(num){
var nums = [];
while(num != 0){
var str = num.toString(),
L = Math.abs(num).toString().length,
MA = str.match(/^(-?[0-9]?[0-9])([0-9][0-9])([0-9][0-9])*$/);
if(MA){
var num1 = MA[1],
num2 = MA[2];
}else{
var num1 = num,
num2 = 0;
}
if(L%2)L++;
if( num2 > 50){
if(num < 0) num1--;
else num1++;
}
nums.push(num1);
var add = parseInt(num1 + Array(--L).join(0),10);
num = (num-add);
}
return nums;
}
reverse_add_subtract(-122436);
First note that each xx group is constrained from [1, 50). This implies that each associated pair in the number that is in the range [50, 99) is really 100 - xx and this means that it "borrowed from" the group to the left. (It also means that there is only one set of normalized numbers and one solution, if any.)
So given the input 23|23|89 (the initial xx spots from -232389), normalize it -- that is, starting from the right, if the value is >= 50, get 100 - value and carry the 100 rightward (must balance). Example: (23 * 100) + 89 = 2300 * 89 = 2400 - 11 = 2389. And example that shows that it doesn't matter if it's negative as the only things that change is the signs: (-23 * 100) - 89 = -2300 - 89 = -2400 + 11 = -2389
(Notes: Remember, 1 is added to the 23 group to make it 24: the sign of the groups is not actually considered in this step, the math is just to show an example that it's okay to do! It may be possible to use this step to determine the sign and avoid extra math below, but this solution just tries to find the candidate numbers at this step. If there are any repeats of the number groups after this step then there is no solution; otherwise a solution exists.)
The candidate numbers after the normalization are then 23|24|11 (let's say this is aa|bb|cc, for below). All the xx values are now known and it is just a matter of finding the combination such that e * (aa * 10000) + f * (bb * 100) + g * (cc * 1) = -232389. The values aa, bb, cc are known from above and e, f, and g will be either 1 or -1, respectively.
Solution Warning: A method of finding the addition or subtraction given the determined numbers (determined above) is provided below the horizontal separator. Take a break and reflect on the above sections before deciding if the extra "hints" are required.
This can then be solved by utilizing the fact that all the xx groups are not dependent after the normalization. (At each step, try to make the input number for the next step approach zero.)
Example:
-232389 + (23 * 10000) = -2389 (e is -1 because that undoes the + we just did)
-2389 + (24 * 100) = 11 (likewise, f is -1)
11 - (11 * 1) = 0 (0 = win! g is 1 and solution is (-1 * 23 * 10000) + (-1 * 24 * 100) + (1 * 11 * 1) = -232389)
Happy homeworking.
First, your math is wrong. Your leading zeros are converting the first two numbers to octal. If that is the intent, the rest of this post doesn't exactly apply but may be able to be adapted.
11-2400-230000 = -232389
Now the last number is easy, it's always the first two digits, 23 in this case. Remove that:
-232389 + 230000 = -2389
Your 2nd number is the next 100 below this, -2400 in this case. And your final number is simply:
-2389 + 2400 = 11
Aww! Someone posted an answer saying "brute force it" that I was about to respond to with:
function find(num){for(var i=1;i<50;i++){for(var o1=0;o1<2;o1++){for(var j=1;j<50;j++){for(var o2=0;o2<2;o2++){for(var k=1;k<50;k++){var eq;if(eval(eq=(i+(o1?'+':'-')+j+'00'+(o2?'+':'-')+k+'0000'))==num){ return eq; }}}}}}}
they deleted it... :(
It was going to go in the comment, but here's a cleaner format:
function find(num){
for(var i=1;i<50;i++){
for(var o1=0;o1<2;o1++){
for(var j=1;j<50;j++){
for(var o2=0;o2<2;o2++){
for(var k=1;k<50;k++){
var eq;
if(eval(eq=(i+(o1?'+':'-')+j+'00'+(o2?'+':'-')+k+'0000'))==num){ return eq; }
}
}
}
}
}
}

get the number of n digit in a 2+ digit number

For example, getting "5" in "256". The closest I've gotten is Math.floor(256/10)), but that'll still return the numbers in front. Is there any simple way to get what I want or would I have to make a big function for it? Also, for clarity: "n digit" would be defined. Example, getDigit(2,256) would return 5 (second digit)
Math.floor((256 / 10) % 10)
or more generally:
Math.floor(N / (Math.pow(10, n)) % 10)
where N is the number to be extracted, and n is the position of the digit. Note that this counts from 0 starting from the right (i.e., the least significant digit = 0), and doesn't account for invalid values of n.
how about
(12345 + "")[3]
or
(12345 + "").charAt(3)
to count from the other end
[length of string - digit you want] so if you want the 2 it's:
5 - 4 = 1
(12345 + "")[1] = "2"
function getNumber (var num, var pos){
var sNum = num + "";
if(pos > sNum.length || pos <= 0){return "";}
return sNum[sNum.length - pos];
}
First, you need to cast the number to a string, then you can access the character as normal:
var num = 256;
var char = num.toString()[1]; // get the 2nd (0-based index) character from the stringified version of num
Edit: Note also that, if you want to access it without setting the number as a variable first, you need a double dot .. to access the function:
var char = 256..toString()[1];
The first dot tells the interpreter "this is a number"; the second accesses the function.
Convert to string and substring(2,2)?
This should do it:
function getDigit ( position, number ) {
number = number + ""; // convert number to string
return number.substr ( position + 1, 1 ); // I'm adding 1 to position, since 0 is the position of the first character and so on
}
Try this, last line is key:
var number = 12345;
var n = 2;
var nDigit = parseInt((number + '').substr(1,1));
If you want to try to do everything mathematically:
var number = 256;
var digitNum = 2;
var digit = ((int)(number/(Math.pow(10,digitNum-1))%10;
This code counts the digit from the right starting with 1, not 0. If you wish to change it to start at 0, delete the -1 portion in the call.
If you wish to count from the left, it gets more complicated and similar to other solutions:
var number = 256;
var digitNum = 2;
var digit = ((int)(number/(Math.pow(10,number.tostring().length-digitNum))%10;
edit:
Also, this assumes you want base 10 for your number system, but both of those will work with other bases. All you need to do is change instances of 10 in the final line of code to the number representing the base for the number system you'd like to use. (ie. hexadecimal =16, binary = 2)
// You do not say if you allow decimal fractions or negative numbers-
// the strings of those need adjusting.
Number.prototype.nthDigit= function(n){
var s= String(this).replace(/\D+/g,'');
if(s.length<=n) return null;
return Number(s.charAt(n))
}
use variable "count" to control loop
var count = 1; //starting 1
for(i=0; i<100; i++){
console.log(count);
if(i%10 == 0) count++;
}
output will fill
1
2
3
4
5
6
7
8
9

Categories

Resources