Random number between negative and positive value [duplicate] - javascript

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Generating random numbers in Javascript in a specific range?
How can i get a random value between, for example, from -99 to 99, excluding 0?

var num = Math.floor(Math.random()*99) + 1; // this will get a number between 1 and 99;
num *= Math.round(Math.random()) ? 1 : -1; // this will add minus sign in 50% of cases
Altogether
var ranNum = Math.ceil(Math.random() * 99) * (Math.round(Math.random()) ? 1 : -1)

This returns what you want
function getNonZeroRandomNumber(){
var random = Math.floor(Math.random()*199) - 99;
if(random==0) return getNonZeroRandomNumber();
return random;
}
Here's a functional fiddle
EDIT
To contribute for future readers with a little debate happened in the comments which the user #MarkDickinson made a indeed relevant contribution to my first code posted, I've decided to make another fiddle with a fast comparison between using Math.floor() and Math.round() functions to return the value the op wanted.
First Scenario: Using var random = Math.round(Math.random()*198) - 99; (My first suggestion)
function getNonZeroRandomNumberWithMathRound(){
var random = Math.round(Math.random()*198) - 99;
if(random==0) return getNonZeroRandomNumber();
return random;
}
Second scenario: Using var random=Math.floor(Math.random()*199) - 99; (Mark suggestion)
function getNonZeroRandomNumberWithMathFloor(){
var random = Math.floor(Math.random()*199) - 99;
if(random==0) return getNonZeroRandomNumber();
return random;
}
Methodology
Since it's a short debate I've chosen fiddle.net to do the comparison.
The test consists of running the above functions 100.000 times and then retrieving how much times the extreme numbers 99 and -99 would appear against a other number, let's say 33 and -33.
The test will then give a simple output consisting of the percentage of appearances from 99 and -99 and the percentage of appearances of 33 and -33.
It'll be used the Webkit implementation from Safari 6.0.2 to the give the output from this answer but anyone can test with your favourite browser late on fiddle.net
Result from first scenario:
Percentage of normal ocurrences:0.97%
Percentage of extreme ocurrences:0.52%
Percentage of extreme ocurrences relative to normal ocurrences:53.4% // Half the chances indeed
Result from second scenario:
Percentage of normal ocurrences:1.052%
Percentage of extreme ocurrences:0.974%
Percentage of extreme ocurrences relative to normal ocurrences:92% //Closer of a fair result with a minimal standard deviation
The result can be seen here: http://jsfiddle.net/brunovieira/LrXqh/

Here's a generalized solution that will let you set the boundaries, and opt in/out of including the 0.
var pos = 99,
neg = 99,
includeZero = false,
result;
do result = Math.ceil(Math.random() * (pos + neg)) - neg;
while (includeZero === false && result === 0);
The pos and neg values are inclusive.
This way there's no requirement that the positive and negative ranges be balanced.
Or if you're worried about the rerun due to a single excluded value, you can just make the initial range less by one, and add 1 to any result greater than or equal to 0.
var pos = 5,
neg = 5,
result;
result = Math.floor(Math.random() * (pos + neg)) - neg;
result = result < 0 ? result : result + 1;
That last line could be shorter if you prefer:
result += (result >= 0)

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))

Return random number excluding specific range - javascript

I'm trying to return a random number within a specific range while also excluding a specific range within it. I've seen similar questions posed, but I can't get it to work. Here's what I have so far:
var x = xFunction();
function xFunction() {
return parseFloat(Math.round(Math.random() * 2250) / 1000).toFixed(3);
}
if (x > 1.250 && x < 2.001 ) {
// this number is excluded so redo xFunction();
} else {
// this number is acceptable so do some code
}
Any help is appreciated. Thank you so much!
One way to handle this is to look for a random number in the range with the excluded part removed. For example if you were looking for a random number between 0 and 100 with 70-80 removed, you would find a random number between 0 and 90 (removing the 10 from the excluded range). Then if any value falls above 70 you add the excluded range back. This will preserve the appropriate ratio of randomness for each range and you should see results mostly from the lower range with a few from the upper range because that is a larger percentage of the distribution.
(I've moved the division and rounding out of the function just to make it clearer how it works.)
function xFunction(max, exclude) {
let excluded_range = exclude[1] - exclude[0]
let rand = Math.random() * (max - excluded_range)
if (rand > exclude[0]) rand += excluded_range
return rand
}
for (let x = 0; x<10; x++){
let r = xFunction(2250, [1250, 2000])
console.log ((r / 1000).toFixed(3));
}
If you pick a random 0 or 1 and use that to determine the range as recommended in the comments, you will end up with approximately half of the result in the much smaller top range. This will bias your results toward that top range rather than truly finding a random number within the whole range.

How to find the closest value of N no. into the sequence?

I have a list of integer sequence:
[10,15,30,45,60,75,90......n*15]
Let's say you have a value i.e. 33
What calculation i should do to find the closest value of 33 into the above sequence?
(JavaScript)
Can we find it without loop?
Thanks.
As others have already pointed out, if you're working with multiples of 15 (assuming the sequence starting with 10 was a mistake), then you can simply do the following:
var interval = 15;
var value = 33;
var closest = Math.round(value / interval) * interval;
console.log(closest);
You didn't specify any language, so here is some pseudocode. Also I assume that the sequence is actually 15*n and there has to be 0 instead of 10 as the first element. Assume the sequence is form 0 to 15*N and the test value is test. IMHO, the simplest algorithm is following:
if(test <= 0)
return 0
else if (test >= 15*N)
return 15*N
else {
lower = Math.floor(test/15)
upper = lower + 1
lowerDif = test - 15*lower
upperDif = 15*upper - test
if (lowerDif < upperDif)
return 15*lower
else
return 15*upper
}
The idea is that you need to check if test is inside [0; 15*N] range. If no - return the boundary, else check two values at indices Math.floor(test/15) and Math.floor(test/15) + 1. It is true that
Math.floor(test/15) <= test < Math.floor(test/15) + 1
So whichever is closer is the answer.

How can I fix these calculations?

I'm taking a number, dividing by 100 and then multiplying it by 100 to have it return to it's original value. Some returned values are a little off however.
var num = 57,
num = num / 100,
// this should return the number to the original
// however in this example it returns 56.99999999999999
num = num * 100;
Here's a fiddle: http://jsfiddle.net/njsdW/
In truth, all I want to do is add two 0's in front of the number, but I'm not always sure where the decimal would be.
EDIT: My solution:
var num = 57,
num = (parseFloat((num / 100).toPrecision(15)));
// this should return the number to the original
num = (parseFloat((num * 100).toPrecision(15)));
You must save the precision of your number and restore it after dividing by 100
prec = num.length;
// adjust for decimal point
if (num.indexOf('.') != -1)
prec--;
// adjust for leading zero
if (num < 1)
prec--;
num /= 100;
self.find('h2').append(num.toPrecision(prec));
JSFiddle
You can use a JavaScript bignum implementation like javascript-bignum or gmp.js to get arbitrary precision. If you want to use gmp.js, you'd have to rewrite your application in C/C++ or write gmp.js bindings for JavaScript. In return, you'd get the battle-tested reliability and optimal algorithmic effenciency from GNU GMP.

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; }
}
}
}
}
}
}

Categories

Resources