Created
June 29, 2016 13:55
-
-
Save suzujun/e0bc7951807eacfa1ca25cfb9f167c2c to your computer and use it in GitHub Desktop.
IEEE 754 規格による浮動小数点数の計算時に生じる誤差を補うため四則演算クラス
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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