Skip to content

Instantly share code, notes, and snippets.

@suzujun
Created June 29, 2016 13:55
Show Gist options
  • Save suzujun/e0bc7951807eacfa1ca25cfb9f167c2c to your computer and use it in GitHub Desktop.
Save suzujun/e0bc7951807eacfa1ca25cfb9f167c2c to your computer and use it in GitHub Desktop.
IEEE 754 規格による浮動小数点数の計算時に生じる誤差を補うため四則演算クラス
/**
* javascript Decimal クラス
*
* IEEE 754 規格による浮動小数点数の計算時に生じる誤差を補うために使用します
*
* example:
* - var a = new utils.Decimal(100).multi(0.0476).calc();
* print(a); // 4.760000000000001 => 4.76
*
* data case:
* - 0.0476 * 100 = 4.760000000000001 ==> 4.76
* - 0.000306 * 1000 = 3.0599999999999996 ==> 3.06
* - 0.05 * 3 = 0.15000000000000002 ==> 0.15
* - 0.01716 * 100000 = 1716.0000000000002 ==> 1716
*
* @see IEEE 754 https://ja.wikipedia.org/wiki/IEEE_754
* @see 元ネタ https://github.com/icoxfog417/simple_decimal
*/
var utils = {};
(function(){
function sDec(value,asRaw){
this.values = [];
this.decimalDigitsMax = 0;
this.add(value || 0);
}
sDec.prototype.valueOf = function(){
return this.value / Math.pow(10, this.decimalDigits);
}
sDec.prototype.toString = function(){
var val = this.valueOf().toFixed(this.decimalDigits).replace(/0+$/,"");
return val;
}
sDec.prototype.val = function(){
return this.value;
}
sDec.prototype.add = function(value, type){
if(!(value === undefined || value == null || value == "")){
if(!isNaN(value)){
var i = String(value).indexOf('.');
var decimalDigits = i >= 0 && String(value).length - i - 1 || 0;
if (this.decimalDigitsMax < decimalDigits) {
this.decimalDigitsMax = decimalDigits;
}
this.values.push({value: value, type: type});
}
}
return this;
}
sDec.prototype.plus = function(value){
return this.add(value, 'plus');
}
sDec.prototype.minus = function(value){
return this.add(value, 'minus');
}
sDec.prototype.multi = function(value){
return this.add(value, 'multi');
}
sDec.prototype.div = function(value){
return this.add(value, 'div');
}
sDec.prototype.calc = function(){
var decimalPart = Math.pow(10, this.decimalDigitsMax);
var result = 0;
this.values.forEach(function(v){
var ret = result;
switch(v.type) {
case 'minus':
result -= Math.round(parseFloat(v.value) * decimalPart);
break;
case 'multi':
var tmp = Math.round(parseFloat(v.value) * decimalPart);
result = result * tmp / decimalPart;
break;
case 'div':
var tmp = Math.round(parseFloat(v.value) * decimalPart);
result = result / tmp * decimalPart;
break;
default: // and 'plus'
result += Math.round(parseFloat(v.value) * decimalPart);
break;
}
});
var i = String(result).indexOf('.');
var decimalDigits = i >= 0 && String(result).length - i - 1 || 0;
var _decimalPart = Math.pow(10, decimalDigits);
return result * _decimalPart / (decimalPart * _decimalPart);
}
utils.Decimal = sDec;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment