Sna*_*Doc 16 javascript floating-point bigdecimal
我是JavaScript的新手(我来自Java背景),我正在尝试用少量资金进行一些财务计算.
我原来的目的是:
<script type="text/javascript">
var normBase = ("[price]").replace("$", "");
var salesBase = ("[saleprice]").replace("$", "");
var base;
if (salesBase != 0) {
base = salesBase;
} else {
base = normBase;
}
var per5 = (base - (base * 0.05));
var per7 = (base - (base * 0.07));
var per10 = (base - (base * 0.10));
var per15 = (base - (base * 0.15));
document.write
(
'5% Off: $' + (Math.ceil(per5 * 100) / 100).toFixed(2) + '<br/>' +
'7% Off: $' + (Math.ceil(per7 * 100) / 100).toFixed(2) + '<br/>' +
'10% Off: $' + (Math.ceil(per10 * 100) / 100).toFixed(2) + '<br/>' +
'15% Off: $' + (Math.ceil(per15 * 100) / 100).toFixed(2) + '<br/>'
);
</script>
Run Code Online (Sandbox Code Playgroud)
这很好用,除了它总是向上舍入(Math.ceil).Math.floor有同样的问题,Math.round对浮子也没有好处.
在Java中,我可以完全避免使用浮点数,但是在JavaScript中似乎没有默认包含的可比性(OMG为什么!?!?!?!).
所以,我的SO-fu带我到这篇文章:https://stackoverflow.com/questions/744099/is-there-a-good-javascript-bigdecimal-library
问题是,提到的所有库都被破坏或用于不同的目的.该jsfromhell.com/classes/bignumber库是非常接近我所需要的,但是我在使用它的舍入和精度......不管我怎么设置圆型来,似乎对自己的决定离奇的问题.因此,例如,3.7107,精度为2,圆形类型ROUND_HALF_UP以3.72为单位,最终为3.72.
我还尝试了@JasonSmith BigDecimal库(来自Java的BigDecimal的机加工端口),但它似乎是针对node.js,我没有选择运行.
我怎样才能使用vanilla JavaScript(并且可靠)来实现这一点,或者是否有一个现代的(上面提到的那些现在已经很久了)我可以使用的库,它被维护并且没有被破坏?
我喜欢使用accounting.js数字,货币和货币格式。
主页-https : //openexchangerates.github.io/accounting.js/
Github - https://github.com/openexchangerates/accounting.js
由于我们对 有本机支持BigInt,因此不再需要太多代码来实现BigDecimal。
这是一个BigDecimal基于BigInt以下特征的类:
BigInt,乘以 10 的幂以包含小数。BigInt值进行。add,subtract,multiply并且divide可以是数字,字符串或实例BigDecimalBigDecimal被视为不可变的。toString方法重新引入小数点。BigDecimal可以强制转换为数字(通过隐式调用toString),但这显然会导致精度损失。class BigDecimal {
// Configuration: constants
static DECIMALS = 18; // number of decimals on all instances
static ROUNDED = true; // numbers are truncated (false) or rounded (true)
static SHIFT = BigInt("1" + "0".repeat(BigDecimal.DECIMALS)); // derived constant
constructor(value) {
if (value instanceof BigDecimal) return value;
let [ints, decis] = String(value).split(".").concat("");
this._n = BigInt(ints + decis.padEnd(BigDecimal.DECIMALS, "0")
.slice(0, BigDecimal.DECIMALS))
+ BigInt(BigDecimal.ROUNDED && decis[BigDecimal.DECIMALS] >= "5");
}
static fromBigInt(bigint) {
return Object.assign(Object.create(BigDecimal.prototype), { _n: bigint });
}
add(num) {
return BigDecimal.fromBigInt(this._n + new BigDecimal(num)._n);
}
subtract(num) {
return BigDecimal.fromBigInt(this._n - new BigDecimal(num)._n);
}
static _divRound(dividend, divisor) {
return BigDecimal.fromBigInt(dividend / divisor
+ (BigDecimal.ROUNDED ? dividend * 2n / divisor % 2n : 0n));
}
multiply(num) {
return BigDecimal._divRound(this._n * new BigDecimal(num)._n, BigDecimal.SHIFT);
}
divide(num) {
return BigDecimal._divRound(this._n * BigDecimal.SHIFT, new BigDecimal(num)._n);
}
toString() {
const s = this._n.toString().padStart(BigDecimal.DECIMALS+1, "0");
return s.slice(0, -BigDecimal.DECIMALS) + "." + s.slice(-BigDecimal.DECIMALS)
.replace(/\.?0+$/, "");
}
}
// Demo
var a = new BigDecimal("123456789123456789876");
var b = a.divide("10000000000000000000");
var c = b.add("9.000000000000000004");
console.log(b.toString());
console.log(c.toString());
console.log(+c); // loss of precision when converting to numberRun Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22287 次 |
| 最近记录: |