[英]divide number with decimals javascript
我怎样才能将数字(钱)平均除以 x 数字,数字可以是一位或两位小数,也可以不带
例如1000
或100.2
或112.34
我希望能够将该数字平均分成 x 部分,但是如果它不是奇数,则额外的数字到最后一个。
例如
3856 / 3
1285.33
1285.33
1285.34
回顾其他答案
重新检查这里提供的解决方案后,我注意到它们产生了一些奇怪的结果。
@GeorgeMauler 的divideCurrencyEqually
似乎适用于原始问题中提供的输入。 但是如果你稍微改变它们,它会产生一个非常奇怪的结果......
// it appears to work
divideCurrencyEvenly(10,3)
=> [ '3.33', '3.33', '3.34' ]
// wups ...
divideCurrencyEvenly(10,6)
=> [ '1.67', '1.67', '1.67', '1.67', '3.32' ]
// hmm this one works ...
divideCurrencyEvenly(18,5)
=> [ '3.60', '3.60', '3.60', '3.60', '3.60' ]
// wups ...
divideCurrencyEvenly(100,7)
=> [ '14.29', '14.29', '14.29', '14.29', '14.29', '28.55' ]
虽然@ Barmar的解决方案似乎更好地履行有点...好一点点......
// it appears to work
divide(10,3)
=> [ '3.33', '3.33', 3.34 ]
// acceptable, i guess
divide(10,6)
=> [ '1.66', '1.66', '1.66', '1.66', '1.66', 1.700000000000001 ]
// hmm, not so good, but still acceptable
divide(18,5)
=> [ '3.60', '3.60', '3.60', '3.60', 3.5999999999999996 ]
// as acceptable as the last two, i guess
divide(100,7)
=> [ '14.28', '14.28', '14.28', '14.28', '14.28', '14.28', 14.320000000000007 ]
像3.5999999999999996
这样的数字大多是可以原谅的,因为这就是JavaScript 中浮点运算的工作原理。
但是,我发现divide
最令人不安的是它给出了一个混合类型的数组(字符串和浮点数)。 而且由于输出中的数字没有四舍五入(到正确的精度),如果您将结果添加到纸上,您将无法返回原始numerator
输入 - 也就是说,除非您对您的数字进行四舍五入结果。
我们仍在为平等而战……
我对上述两种解决方案也存在最后的不满。 结果并不代表尽可能接近相等的分布。
如果以 2 的精度将 100 除以 7,@Barmar 的解决方案(修复了舍入问题)将给出……
[ '14.28', '14.28', '14.28', '14.28', '14.28', '14.28', 14.32 ]
如果这些是人,而且数字代表金钱,那么1 个人不应该多付4 便士。 相反, 4 个人应该多付1 分钱……
[ 14.29, 14.29, 14.29, 14.29, 14.28, 14.28, 14.28 ]
尽可能接近相等
回到第一个广场
我对解决方案不满意,所以我自己做了一个, distribute
.
它有 3 个参数:精度p
、除数d
和分子n
。
它缩放分子并找到最大的整数q
,其中q * d <= n
。 使用模除法,我们知道需要贡献多少“切片” q+1
。 最后,每个q
或q+1
都按比例缩小并填充输出数组。
const fill = (n, x) => Array (n) .fill (x) const concat = (xs, ys) => xs .concat (ys) const quotrem = (n, d) => [ Math .floor (n / d) , Math .floor (n % d) ] const distribute = (p, d, n) => { const e = Math .pow (10, p) const [ q, r ] = quotrem (n * e, d) return concat ( fill (r, (q + 1) / e) , fill (d - r, q / e) ) } console .log ( distribute (2, 3, 10) // [ 3.34, 3.33, 3.33 ] , distribute (2, 6, 10) // [ 1.67, 1.67, 1.67, 1.67, 1.66, 1.66 ] , distribute (2, 5, 18) // [ 3.6, 3.6, 3.6, 3.6, 3.6 ] , distribute (2, 7, 100) // [ 14.29, 14.29, 14.29, 14.29, 14.28, 14.28, 14.28 ] )
您会看到我将 precision 设置为参数p
,这意味着您可以控制出现的小数位数。 还要注意结果中任何数字之间的最大差异Δ
如何是Δ <= 1/10^p
distribute (0, 7, 100)
=> [ 15, 15, 14, 14, 14, 14, 14 ] // Δ = 1
distribute (1, 7, 100)
=> [ 14.3, 14.3, 14.3, 14.3, 14.3, 14.3, 14.2 ] // Δ = 0.1
distribute (2, 7, 100)
=> [ 14.29, 14.29, 14.29, 14.29, 14.28, 14.28, 14.28 ] // Δ = 0.01
distribute (3, 7, 100)
=> [ 14.286, 14.286, 14.286, 14.286, 14.286, 14.285, 14.285 ] // Δ = 0.001
distribute (4, 7, 100)
=> [ 14.2858, 14.2857, 14.2857, 14.2857, 14.2857, 14.2857, 14.2857 ] // Δ = 0.0001
distribute
可以以有意义的方式被部分地施加。 这是小人可以使用它在餐厅精确分摊账单的一种方式......
// splitTheBill will use precision of 2 which works nice for monies
const splitTheBill = (people, money) =>
distribute (2, people, money)
// partyOfThree splits the bill between 3 people
const partyOfThree = money =>
splitTheBill (3, money)
// how much does each person pay ?
partyOfThree (67.89)
=> [ 18.93, 18.93, 18.92 ]
这是将人们分成小组的有效方法——同时注意不要将一个人分开——这通常会导致死亡……
// p=0 will yield only whole numbers in the result
const makeTeams = (teams, people) =>
distribute (0, teams, people)
// make 4 teams from 18 people
// how many people on each team?
makeTeams (4, 18)
=> [ 5, 5, 4, 4 ]
function divide(numerator, divisor) {
var results = [];
var dividend = (Math.floor(numerator/divisor*100)/100).toFixed(2); // dividend with 2 decimal places
for (var i = 0; i < divisor-1; i++) {
results.push(dividend); // Put n-1 copies of dividend in results
}
results.push(numerator - (divisor-1)*dividend); // Add remainder to results
return results;
}
听起来像一个非常简单的循环/递归。
function divideEvenly(numerator, minPartSize) {
if(numerator / minPartSize< 2) {
return [numerator];
}
return [minPartSize].concat(divideEvenly(numerator-minPartSize, minPartSize));
}
console.log(divideEvenly(1000, 333));
要使其成为货币的两位小数,在调用此函数之前将两个数字乘以 100,然后将每个结果除以 100 并调用toFixed(2)
。
function divideCurrencyEvenly(numerator, divisor) {
var minPartSize = +(numerator / divisor).toFixed(2)
return divideEvenly(numerator*100, minPartSize*100).map(function(v) {
return (v/100).toFixed(2);
});
}
console.log(divideCurrencyEvenly(3856, 3));
//=>["1285.33", "1285.33", "1285.34"]
由于我们在谈论金钱,通常只要总数正确加起来,几美分的差异并不重要。 因此,如果您不介意一笔付款可能比其他付款多几美分,这里有一个非常简单的分期付款解决方案。
function CalculateInstallments(total, installments) { // Calculate Installment Payments var pennies = total * 100; var remainder = pennies % installments; var otherPayments = (pennies - remainder) / installments; var firstPayment = otherPayments + remainder; for (var i = 0; i < installments; i++) { if (i == 0) { console.log("first payment = ", firstPayment / 100); } else { console.log("next payment = ", otherPayments / 100); } } }
既然你说你想要最后的最高付款,你会想要修改 for 循环中的 if 语句: if (i==installments-1) { //last payment }
@user633183 的distribute
存在问题,但仅在分频器低于 3 时才会发生。
distribute(2, 2, 560.3)
// [ '280.15' , '280.14']
distribute(2, 1, 74.10)
// [ '74.09' ]
distribute(2, 1, 74.60)
// [ '74.59' ]
我把Guffa的答案改写成了 javascript
const distribute = (precision, divider, numerator) => {
const arr = [];
while (divider > 0) {
let amount = Math.round((numerator / divider) * Math.pow(10, precision)) / Math.pow(10, precision);
arr.push(amount);
numerator -= amount;
divider--;
}
return arr.sort((a, b) => b-a);
};
这是结果
distribute(0, 7, 100)
=> [ 15, 15, 14, 14, 14, 14, 14 ]
distribute(1, 7, 100)
=> [ 14.3, 14.3, 14.3, 14.3, 14.3, 14.3, 14.2 ]
distribute(2, 7, 100)
=> [ 14.29, 14.29, 14.29, 14.29, 14.28, 14.28, 14.28 ]
distribute(3, 7, 100)
=> [ 14.286, 14.286, 14.286, 14.286, 14.286, 14.285, 14.285 ]
distribute(4, 7, 100)
=> [ 14.2858, 14.2857, 14.2857, 14.2857, 14.2857, 14.2857, 14.2857 ]
// and of course
distribute(2, 2, 560.3)
=> [ 280.15, 280.15 ]
distribute(2, 1, 74.10)
=> [ 74.1 ]
distribute(2, 1, 74.60)
=> [ 74.6 ]
请检查以下代码,
function Dividently(Amount, Quantity) {
var m = Amount* 100,
n = m % Quantity,
v = Math.floor(m / Quantity) / 100,
w = Math.floor(m / Quantity+ 1) / 100;
for (var i = 0, out = new Array(Quantity); i < Quantity; ++i) {
out[i] = i < n ? w : v;
}
return out;
}
var arr = Dividently(3856, 3);
Math.floor() - 将数字向下舍入到最接近的整数
如果有人正在寻找随机分布的 vanilla JS 解决方案,这里是我的:
function fairDivision(resolution, numerator, denominator) {
// preserves numerator(n) integrity when dividing into denominator(d) bins
// remainders are randomly distributed into sequential bins
// resolution is number of significant digits after decimal
// (-'ve resolution for insignificant digits before decimal).
const n = numerator * Math.pow(10, resolution);
const remainder = n % denominator;
const base = (n - remainder) / denominator;
const offset = Math.floor(Math.random()*denominator); // index of first 'round-up' bin
let arr = []
let low= (offset + remainder) % denominator;
let a; let b; let c = (low < offset); //logical units
for (let i=0; i < denominator; i++) {
a = (i < low);
b = (i >= offset);
if ((a && b) || (a && c) || (b && c)) {
arr.push(base +1)
} else{
arr.push(base)
}
arr[i] = arr[i] / Math.pow(10, resolution);
}
return arr;
}
这是基于@Thank_you 的结论,只是为了在平等的基础上划分没有小数的部分:
//n=how many groups, lot = total units
function makeTeams2(n,lot){
var div = lot/n;
var portion = Math.floor(div);
var remains = Math.round(n*((div) % 1));
var arr = [];
for(var i=0; i<n; i++) arr.push(portion);
for(var i=0; i<remains; i++) arr[i] = arr[i] + 1;
return arr;
}
// >> makeTeams2(7,100);
// >> [15,15,14,14,14,14,14]
这比@Thank_you 的 "makeTeams(teams,people)" 常量快一点,但我接受性能改进,因为我是初学者,我只是以自己的方式做到了这一点并想分享。
<button onclick="myFunction(3856,3)">Try it</button>
function myFunction(number,divide) {
var money = number / divide;
money = Math.ceil(money * 100) / 100;
alert(money); //1285.34
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.