How to determine if a number is tenthousandth, thousandth, hundredth, tens. I need to convert them to their nearest.
For example, 124. since it's hundredth, i will convert it to 200 using
Math.ceil(124/100) * 100
For example, 4560. since it's thousandth, i will convert it to 5000 using
Math.ceil(5000/1000) * 1000
you can use the following way to convert given number into nearest 10
function convertToNearest(num){
var mul = 1;
while(num > (mul * 10))
mul = mul * 10;
return Math.ceil(num/mul) * mul;
}
This solution handles integers (positive AND negative):
function nearest(n) {
if (n === 0)
return 0;
let neg = (n < 0);
if (neg)
n = -n;
let x = 10 ** Math.floor(Math.log10(n));
if (x === 1)
x = 10;
let ans = Math.ceil(n/x) * x;
return (neg) ? -ans : ans;
}
[-230, 0, 1, 8, -18, -6540, -120, -5, 12, 4560, 320, 888, 83293, 2323203]
.forEach(n => console.log('%s\t->\t%s', n, nearest(n)));
Related
I'trying to make a function creates a list of exponentially increasing numbers where the sum of the numbers is equal to some maximum.
For example:
/*
* What do I have to raise N by in order for the sum to be 40
*/
(1**x + 2**x + 3**x + 4**x + 5**x) === 40;
/*
* Wolframalpha tells me: x = 1.76445
* But how can I solve with JS.
*/
function listOfNumbers(n, maxSum) {
// implementation
}
var result = listOfNumbers(5, 40);
/*
* result === [1, 3.397..., 6.947..., 11.542..., 17.111...]
*
*/
result.reduce((acc, n) => acc += n) === 40
try https://en.wikipedia.org/wiki/Bisection_method
TOLERANCE = 1e-5;
let f = x => (1 ** x + 2 ** x + 3 ** x + 4 ** x + 5 ** x - 40);
let
min = 0,
max = 1,
x = 0;
// roughly locate the upper bound
while (f(max) < 0)
max *= 2;
// repeatedly bisect the interval [min, max]
while (1) {
x = (min + max) / 2;
let r = f(x);
if (Math.abs(r) < TOLERANCE)
break;
if (r > 0) {
max = x
} else {
min = x
}
}
// now, x is a "good enough" approximation of the root
console.log(x);
I have the following function that generates a random boolean.
choose_direction: function () {
var random_boolean = Math.random() >= 0.5;
if (random_boolean) {
trade.call()
prev_trade.goingUp = true
console.log('Trade: CALL!!!!!!!!!!!!!!!!!!!!!!')
} else {
trade.put()
prev_trade.goingUp = false
console.log('Trade: PUT!!!!!!!!!!!!!!!!!!!!!!!!')
}
}
However, I need the distribution to be unfair. More specifically, I want the output to be 70% of the time true and 30% of the time false.
Instead of >= 0.5 you just need < 0.7:
var random_boolean = Math.random() < 0.7;
// 70% this will be true, 30% false
As #plasmacel commented, Math.random() returns a value between 0 and 1 (including 0, but not 1: [0, 1)), so therefore we do < 0.7.
Let's consider one thing. Math.random() gives you a pseudo-random number.
Try this function:
function randomTest(triesCount) {
var sum = 0;
for(var i = 0; i < triesCount; i++){
sum += Math.random();
}
return sum / triesCount;
}
if you try it with different triesCount parameters the results will be:
randomTest(100) - 0.5189474703446081
randomTest(100) - 0.5189474703446081
randomTest(1000) - 0.4973368682657417
randomTest(10000) - 0.5001058467610172
randomTest(100000) - 0.4987280984186288
randomTest(1000000) - 0.4999987387801045
randomTest(10000000) - 0.49998292815655454
randomTest(100000000) - 0.500079160302315
So as you can se the results go to 0.5 which means this is not a random number generated here.
Although the answer to your question will be
var random_boolean = Math.random() >= 0.3;
as Ionică Bizău said.
But keep in mind that it is pseudo-random number!
Here is a version I made with typescript. Can easily remove the variable types to turn this into javascript.
//Usage
let randomBoolean = randomPercentForTrue(70)
export function randomPercentForTrue(percentage: number): boolean {
return randomNumber(1, 100) <= percentage
}
export function randomNumber(minValue: number, maxValue: number): number {
return Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue
}
These methods are heavily tested with various use cases. Here are test cases with mocha:
it('randomPercentForTrue with 95% accuracy', function() {
let results0: boolean[] = []
let results1: boolean[] = []
let results2: boolean[] = []
let results3: boolean[] = []
let results4: boolean[] = []
let loopAmount = 10000
for(let i = 0; i < loopAmount; i++) {
results0.push(randomPercentForTrue(0))
results1.push(randomPercentForTrue(25))
results2.push(randomPercentForTrue(50))
results3.push(randomPercentForTrue(75))
results4.push(randomPercentForTrue(100))
}
let resultTotals = Array(5).fill(0)
for(let i = 0; i < loopAmount; i++) {
resultTotals[0] += results0[i]
resultTotals[1] += results1[i]
resultTotals[2] += results2[i]
resultTotals[3] += results3[i]
resultTotals[4] += results4[i]
}
expect(resultTotals[0]).to.be.closeTo(0, 0)
expect(resultTotals[1]).to.be.closeTo(loopAmount * 25 / 100, loopAmount * 25 / 100 / 20)
expect(resultTotals[2]).to.be.closeTo(loopAmount * 50 / 100, loopAmount * 50 / 100 / 20)
expect(resultTotals[3]).to.be.closeTo(loopAmount * 75 / 100, loopAmount * 75 / 100 / 20)
expect(resultTotals[4]).to.be.closeTo(loopAmount, 0)
})
Had a hard time coming up with a concise title for this. I'm sure there are terms for what I want to accomplish and there is no doubt a common algorithm to accomplish what I'm after - I just don't know about them yet.
I need to break up a number into n pieces that are each a multiple of 50. The number is itself a multiple of 50. Here is an example:
Divide 5,000 by 3 and end up with three numbers that are each multiples of 50:
1,650
1,700
1,650
I also would like to have the numbers distributed so that they flip back and forth, here is an example with more numbers to illustrate this:
Divide 5,000 by 7 and end up with 7 numbers that are each multiples of 50:
700
750
700
750
700
700
700
Note that in the above example I'm not worried that the extra 50 is not centered in the series, that is I don't need to have something like this:
700
700
750 <--- note the '50s' are centered
700
750 <--- note the '50s' are centered
700
700
Hopefully I've asked this clearly enough that you understand what I want to accomplish.
Update: Here is the function I'll be using.
var number = 5000;
var n = 7;
var multiple = 50;
var values = getIntDividedIntoMultiple(number, n, multiple)
function getIntDividedIntoMultiple(dividend, divisor, multiple)
{
var values = [];
while (dividend> 0 && divisor > 0)
{
var a = Math.round(dividend/ divisor / multiple) * multiple;
dividend -= a;
divisor--;
values.push(a);
}
return values;
}
var number = 5000;
var n = 7;
var values = [];
while (number > 0 && n > 0) {
var a = Math.floor(number / n / 50) * 50;
number -= a;
n--;
values.push(a);
} // 700 700 700 700 700 750 750
Edit
You can alternate Math.floor and Math.ceil to obtain the desired result:
while (number > 0 && n > 0) {
if (a%2 == 0)
a = Math.floor(number / n / 50) * 50;
else
a = Math.ceil(number / n / 50) * 50;
number -= a;
n--;
values.push(a);
} // 700 750 700 750 700 700 700
// i - an integer multiple of k
// k - an integer
// n - a valid array length
// returns an array of length n containing integer multiples of k
// such that the elements sum to i and the array is sorted,
// contains the minimum number of unique elements necessary to
// satisfy the first condition, the elements chosen are the
// closest together that satisfy the first condition.
function f(i, k, n) {
var minNumber = (((i / k) / n) | 0) * k;
var maxNumber = minNumber + k;
var numMax = (i - (minNumber * n)) / k;
var nums = [];
for (var i = 0; i < n - numMax; ++i) {
nums[i] = minNumber;
}
for (var i = n - numMax; i < n; ++i) {
nums[i] = maxNumber;
}
return nums;
}
So your second example would be
f(5000, 50, 7)
which yields
[700,700,700,700,700,750,750]
Let a be your starting number, k - number of parts you want to divide to.
Suppose, that b = a/n.
Now you want to divide b into k close integer parts.
Take k numbers, each equal to b/k (integer division).
Add 1 to first b%k numbers.
Multiply each number by n.
Example:
a = 5000, n = 50, k = 7.
b = 100
Starting series {14, 14, 14, 14, 14, 14, 14}
Add 1 to first 2 integers {15, 15, 14, 14, 14, 14, 14}.
Multiply by 50 {750, 750, 700, 700, 700, 700, 700}.
Your problem is the same as dividing a number X into N integer pieces that are all within 1 of each other (just multiply everything by 50 after you've found the result). Doing this is easy - set all N numbers to Floor(X/N), then add 1 to X mod N of them.
I see your problem as basically trying to divide a sum of money into near-equal bundles of bills of a certain denomination.
For example, dividing 10,000 dollars into 7 near-equal bundles of 50-dollar bills.
function getBundles(sum, denomination, count, shuffle)
{
var p = Math.floor(sum / denomination);
var q = Math.floor(p / count);
var r = p - q * count;
console.log(r + " of " + ((q + 1) * denomination)
+ " and " + (count - r) + " of " + (q * denomination));
var b = new Array(count);
for (var i = 0; i < count; i++) {
b[i] = (r > 0 && (!shuffle || Math.random() < .5 || count - i == r)
? (--r, q + 1) : q)
* denomination;
}
return b;
}
// Divide 10,000 dollars into 7 near-equal bundles of 50-dollar bills
var bundles = getBundles(10000, 50, 7, true);
console.log("bundles: " + bundles);
Output:
4 of 1450 and 3 of 1400
bundles: 1400,1450,1450,1400,1450,1400,1450
If the last argument shuffle is true, it distributes the extra amount randomly between the bundles.
Here's my take:
public static void main(String[] args) {
System.out.println(toList(divide(50, 5000, 3)));
System.out.println(toList(divide(50, 5000, 7)));
System.out.println(toList(divide(33, 6600, 7)));
}
private static ArrayList<Integer> toList(int[] args) {
ArrayList<Integer> list = new ArrayList<Integer>(args.length);
for (int i : args)
list.add(i);
return list;
}
public static int[] divide(int N, int multiplyOfN, int partsCount) {
if (N <= 0 || multiplyOfN <= N || multiplyOfN % N != 0)
throw new IllegalArgumentException("Invalid args");
int factor = multiplyOfN / N;
if (partsCount > factor)
throw new IllegalArgumentException("Invalid args");
int parts[] = new int[partsCount];
int remainingAdjustments = factor % partsCount;
int base = ((multiplyOfN / partsCount) / N) * N;
for (int i = 0; i < partsCount; i ++) {
parts[i] = (i % 2 == 1 && remainingAdjustments-- > 0) ? base + N : base;
}
return parts;
}
My algorithm provides even distribution of remainder across parts:
function splitValue(value, parts, multiplicity)
{
var result = [];
var currentSum = 0;
for (var i = 0; i < parts; i++)
{
result[i] = Math.round(value * (i + 1) / parts / multiplicity) * multiplicity - currentSum;
currentSum += result[i];
}
return result;
}
For value = 5000, parts = 7, multiplicity = 50 it returns
[ 700, 750, 700, 700, 700, 750, 700 ]
Hi I need to generate a random number in JavaScript between 15 and 225 that can only be by increments of 30. For example: 45, 75, 105 etc.
Any ideas on how this can be done? I'm aware of Math.floor(Math.random()*11) for example for a random number 1-10 but how can this be modified to fit in with what I'm trying to do?
Like so
Math.floor(Math.random()*8)*30 + 15
how about using:
[15, 45, 75, 105, 135, 165, 195, 225][Math.floor(Math.random()*8)]
Start with the table of values
x | y
=======
0 | 15
1 | 45
2 | 75
3 | 105
4 | 135
5 | 165
6 | 195
7 | 225
Set up the equation
y = ax + b
Plug in some initial values
15 = a(0) + b
Solve for any variables you can
15 = b
Plug in different initial values
225 = a(7) + 15
Solve for any remaining variables
210 = a(7)
30 = a
Restate the equation
y = 30x + 15
Randomize x between the limits
x = Math.floor(Math.random() * 8) //0-7
Use in function
function customRandomNumber() {
var x;
x = Math.floor(Math.random() * 8);
return 30 * x + 15;
}
Getting a random number within an interval with a step can be generalized in the following function:
function rand(min, max, step) {
var delta,
range,
rand;
if (arguments.length < 2) {
max = min;
min = 0;
}
if (!step) {
step = 1;
}
delta = max - min;
range = delta / step;
rand = Math.random();
rand *= range;
rand = Math.floor(rand);
rand *= step;
rand += min;
return rand;
}
Which would put your function as
rand(15, 225, 30);
I should also note, because I'd forgotten about the possible bounds issues, the generalized form will not include the upper bound of 225. This is because Math.random() returns a number greater than, or equal to zero and less than one (0 <= Math.random < 1). If you want to include the upper bound, you simply need to include one more step in the interval:
rand(15, 255, 30) //will return 15...225
You need to think about the final outcome that you want. Between 15 and 225 is what you want to aim for, but not what you need to be working with to get the result.
225/30 = 7.5. 15 is half of 30. Therefore, (225-15)/30 = 7. You want a random number between 1 and 7, which you will then multiply by 30 and add 15 to the final result.
var myNumber = Math.floor(Math.random()*7);
myNumber = myNumber *30 + 15;
console.log(myNumber);
Here's a function that precomputes all possible numbers, and randomly returns one.
function getRandomNumber(start, end, increments) {
var numbers = [];
for(var n = start; n <= end; n += increments) {
numbers.push(n);
}
var randomIndex = Math.floor(Math.random() * numbers.length);
return numbers[randomIndex];
}
Use as,
getRandomNumber(15, 225, 30)
Here's a generic version.
function randomIntInSteps(a, b, step) {
function randomInt(a, b) {
return Math.floor(Math.random() * (b - a + 1) + a);
}
if (a > b) {
// Ensure a is smaller.
var c = a;
a = b;
b = c;
}
step = Math.abs(step)
return a + randomInt(0, Math.floor((b - a)/step)) * step;
}
It can be used like this:
randomIntInSteps(1, 20, 5); // possible results: 1, 6, 11, 16
randomIntInSteps(1, 21, 5); // possible results: 1, 6, 11, 16, 21
It will also work with negatives:
randomIntInSteps(-10, 11, 5); // possible results: -10, -5, 0, 5, 10
randomIntInSteps(-20, -9, 5); // possible results: -20, -15, -10
Using floats can be problematic because of floating point errors:
randomIntInSteps(1.1, 5.5, 2.2); // possible results: 1.1, 3.3000000000000003, 5.5
To overcome the floating point problem, you can convert the numbers to integers before finding a random number, then convert back. Here's how (note: this depends on the randomIntInSteps function above, so you still need that):
function decimalPlaces(number) {
var parts = (number + '').split('.');
return parts.length > 1 ? parts[1].length : 0;
}
function wholeNumberMultiple(numbers) {
return Math.max(...numbers.map(n => decimalPlaces(n)));
}
function randomNumber(a, b, step) {
var multiple = Math.pow(10, wholeNumberMultiple([a, b]));
return randomIntInSteps(a * multiple, b * multiple, step * multiple) / multiple;
}
You'll now get the desired results:
randomNumber(1.1, 5.5, 2.2); // possible results: 1.1, 3.3, 5.5
Okay....
I have a lot of uncontrolled numbers i want to round:
51255 -> 55000
25 -> 25
9214 -> 9500
13135 -> 15000
25123 -> 30000
I have tried modifying the numbers as string and counting length....
But is there a simple way using some Math function maybe?
Here's my late answer. Uses no Math methods.
function toN5( x ) {
var i = 5;
while( x >= 100 ) {x/=10; i*=10;}
return ((~~(x/5))+(x%5?1:0)) * i;
}
DEMO: http://jsbin.com/ujamoj/edit#javascript,live
[51255, 24, 25, 26, 9214, 13135, 25123, 1, 9, 0].map( toN5 );
// [55000, 25, 25, 30, 9500, 15000, 30000, 5, 10, 0]
Or this is perhaps a bit cleaner:
function toN5( x ) {
var i = 1;
while( x >= 100 ) {x/=10; i*=10;}
return (x + (5-((x%5)||5))) * i;
}
DEMO: http://jsbin.com/idowan/edit#javascript,live
To break it down:
function toN5( x ) {
// v---we're going to reduce x to the tens place, and for each place
// v reduction, we'll multiply i * 10 to restore x later.
var i = 1;
// as long as x >= 100, divide x by 10, and multiply i by 10.
while( x >= 100 ) {x/=10; i*=10;}
// Now round up to the next 5 by adding to x the difference between 5 and
// the remainder of x/5 (or if the remainder was 0, we substitute 5
// for the remainder, so it is (x + (5 - 5)), which of course equals x).
// So then since we are now in either the tens or ones place, and we've
// rounded to the next 5 (or stayed the same), we multiply by i to restore
// x to its original place.
return (x + (5-((x%5)||5))) * i;
}
Or to avoid logical operators, and just use arithmetic operators, we could do:
return (x + ((5-(x%5))%5)) * i;
And to spread it out a bit:
function toN5( x ) {
var i = 1;
while( x >= 100 ) {
x/=10;
i*=10;
}
var remainder = x % 5;
var distance_to_5 = (5 - remainder) % 5;
return (x + distance_to_5) * i;
}
var numbers = [51255, 25, 9214, 13135, 25123, 3, 6];
function weird_round(a) {
var len = a.toString().length;
var div = len == 1 ? 1 : Math.pow(10, len - 2);
return Math.ceil(a / 5 / div) * div * 5;
}
alert(numbers.map(weird_round));
Also updated for numbers below 10. Won't work properly for negative numbers either, just mention if you need this.
DEMO
I'm not sure why, but I thought it would be fun with regular expressions:
var result = +(number.toString().replace(/([1-9])([0-9])(.+)/, function() {
return Math.ceil(+(arguments[1] + '.' + arguments[2])) * 10 - (+arguments[2] < 5?5:0) + arguments[3].replace(/./g, '0');
}));
Working Demo
with(Math) {
var exp = floor(log(number)/log(10)) - 1;
exp = max(exp,0);
var n = number/pow(10,exp);
var n2 = ceil(n/5) * 5;
var result = n2 * pow(10,exp);
}
http://jsfiddle.net/NvvGf/4/
Caveat: only works for the natural numbers.
function round(number) {
var numberStr = number + "",
max,
i;
if (numberStr[1] > '4') {
numberStr[0] = parseInt(numberStr[0]) + 1;
numberStr[1] = '0';
} else {
numberStr[1] = '5';
}
for (i = 2; max = numberStr.length; i < max; i += 1) {
numberStr += '0';
}
return parseInt(numberStr);
}
Strange coincidence, I wrote something really similar not so long ago!
function iSuckAtNames(n) {
var n = n.toString(), len = n.length, res;
//Check the second number. if it's less than a 5, round down,
//If it's more/equal, round up
//Either way, we'll need to use this:
var res = parseFloat(n[0]) * Math.pow(10, len - 1); //e.g. 5 * 10^4 = 50000
if (n[1] <= 5) {
//we need to add a 5 right before the end!
res += 5 * Math.pow(10, len - 2);
}
else {
//We need another number of that size
res += Math.pow(10, len - 1);
}
return res;
}