計算中のみ一時的に10とか100などの数字をかけて整数にして、最後に桁を元通りにすれば上記の問題を回避できます。
そのための関数を作成しました。
以下ソース
This file contains 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
<job> | |
<script> | |
LEN='length' | |
forIn = function(obj,fun){var name,res; for(name in obj){if(res=fun(name, obj[name])){return res}}} | |
switch(2){ | |
case 0: | |
// 以下では「66.9+0.01」の結果が「66.89000000000001」になってしまう。 | |
整数化=function(){ | |
var reg=/\.(\d+)/, get桁数=function(num){return (num+'').match(reg) ? RegExp.$1.length : 0} | |
var obj0, arr0, arr0L, obj1, forIn用=function(name,v){ arr0[arr0L++]=get桁数(v) }, max, x, 反映=function(name,v){ obj1[name] = v * x } | |
var check=function(name,v){(v+'').match(reg) && WScript.Echo([v,x].join('\n'))} | |
return function(obj, fun){ | |
arr0 = [] | |
arr0L= 0 | |
obj1 = {} | |
forIn(obj0=obj, forIn用) | |
max=Math.max.apply(null, arr0), x=(1+Array(max+1).join(0))-0 | |
forIn(obj0, 反映) | |
forIn(obj1, check) | |
return fun(obj1) / x | |
} | |
}() | |
break | |
case 1: | |
// 以下では「1.234e-16」のような値に対応できない。 | |
整数化=function(){ | |
var reg=/\.(\d+)/, arr, arrL, obj0 | |
var getObj=function(num){ | |
var str=num+'', obj={元:num, str:str.replace(reg,'$1'), 桁数:arr[arrL++]=RegExp.$1.length} | |
return obj | |
} | |
return function(obj, func){ | |
arr = [] | |
arrL = 0 | |
obj0 = {} | |
forIn(obj,function(name, v){ obj0[name] = getObj(v) }) | |
var max=Math.max.apply(null, arr), obj1={} | |
forIn(obj0,function(name, v){ | |
obj1[name] = (v.str + Array(max-v.桁数+1).join(0)) - 0 | |
// 万が一整数化に失敗した場合はどのような値で失敗したのか通知する。 | |
if(0<(''+obj1[name]).indexOf('.')){ WScript.Echo('整数化失敗\n'+obj1[name]+'\nstr:'+v.str) } | |
}) | |
return func(obj1) / (1+Array(max+1).join(0)) | |
} | |
}() | |
break | |
case 2: | |
整数化=function(){ | |
var regDot=/\.(\d+)/, regE=/\.(\d+)e-(\d+)/, arr, arrL, obj0 | |
var getObj=function(num){ | |
var str=num+'', 桁数=0 | |
while(1){ | |
if(str.match(regE )){ 桁数=RegExp.$2-(-3) ; str=str.replace(regE ,'$1'); break } | |
if(str.match(regDot)){ 桁数=RegExp.$1.length; str=str.replace(regDot,'$1'); break } | |
break | |
} | |
return {元:num, str:str, 桁数:arr[arrL++]=桁数} | |
} | |
return function(obj, func){ | |
arr = [] | |
arrL = 0 | |
obj0 = {} | |
forIn(obj,function(name, v){ obj0[name] = getObj(v) }) | |
var max=Math.max.apply(null, arr), obj1={} | |
forIn(obj0,function(name, v){ | |
obj1[name] = (v.str + Array(max-v.桁数+1).join(0)) - 0 | |
// 言語で扱える数字のサイズを超えてしまった場合は通知する。 | |
if(!isFinite(obj1[name])){ alert('整数化失敗\nisFinite=false\n'+obj[name]+'\nstr:'+str) } | |
// 万が一整数化に失敗した場合はどのような値で失敗したのか通知する。 | |
if(0<(''+obj1[name]).indexOf('.') && !(''+obj1[name]).match(/e\+/)){ WScript.Echo('整数化失敗\n'+obj1[name]+'\nstr:'+v.str) } | |
}) | |
return func(obj1) / (1+Array(max+1).join(0)) | |
} | |
}() | |
break | |
} | |
a = -20.41 | |
b = -43.3 | |
c = a - b | |
d = 整数化({a:a, b:b}, function(obj){return obj.a - obj.b}) | |
e = 66.9 | |
f = 0.01 | |
g = 整数化({e:e, f:f}, function(obj){return obj.e - obj.f}) | |
h = 90071992547409.92 | |
i = 1.234e-16 | |
j = 整数化([h,i], function(arr){return arr[0] - arr[1]}) | |
// 22.889999999999997 | |
// 22.89 | |
WScript.Echo([c,d,g,j].join('\n')) | |
</script> | |
</job> |
実行結果
0 件のコメント:
コメントを投稿