最近我编写我的数据分析器程序时,我遇到了一个问题:JavaScript浮点数计算时会有偏差。例如19.6除以10不等于1.96000000000002

我尝试在网上查找资料,但没有足够的解决方案来解决我的问题。有些解决方案对我的程序没有帮助,它们仍然存在误差。

我有很强的计算机编程能力,能耐心、成功地解决很多个编程问题。 查看我的技能

我保持冷静,一小时后我自己想到了一个解决办法。现在,我将分享我的解决方案来解决你的问题。


什么是JavaScript中的计算误差?

在JavaScript中,计算浮点数会导致误差,结果不准确,并且我需要避开这个问题。

在浮点数(不是整数)中,当加、减、乘、除或使用Math.pow(a, b);时会发生这种情况。

如果两个数字都是整数,即使结果不是整数,结果也将是准确的。

例如19.6除以10不等于1.96000000000002,因为19.6不是整数,即使10是整数。


我是怎么解决这个问题的?

准确计算是不容易的,我们需要使用这么多的代码来确保结果的准确性。所以我把代码放到函数(Function)中,你只需要调用函数来进行准确计算。

我有一个想法来解决这个问题:将浮点数乘以10、100、1000等,而不使用parseInt();、Math.floor();、Math.round();或Math.ceil();函数。然后再把结果除回去。

我用一种特殊的方法来乘两个数字,因为乘10也有可能不准确。它将几个零作为一个字符串添加,然后添加到数字中(它将数字转换为字符串),并使用parseInt();将它们转换回整数。

例如,有两个数字a和b,我们通常用“a/b”来计算除法,这是不准确的。我的方法将会查看两个数字的小数位数,并保存较大的小数位数c。如果a和b都是整数,则函数将计算而不做任何修改。如果c=1,则乘以10,如果c=2,则乘以100,如果c=3,则乘以1000,等等,然后计算a和b,再将结果除回去,返回最终结果。


我的解决方法代码

最后更新:2019年7月27日 23:30

修复了一些数仍然有误差的bug

将下面的代码复制并粘贴到JavaScript脚本的顶部,还可以将其保存为.js文件并重复使用。

// This function is used to prevent the deviation for adding
// 此方法用于防止加法误差
function accAdd(arg1, arg2) {
	var zeros1 = "";
	var zeros2 = "";
	var xiaoShuWeiShu1 = 0;
	var xiaoShuWeiShu2 = 0;
	var arg11 = 0;
	var arg21 = 0;
	if((arg1 + "").includes(".")){
		xiaoShuWeiShu1 = (arg1+"").split(".")[1].length;
	}else{
		xiaoShuWeiShu1 = 0;
	}
	if((arg2 + "").includes(".")){
		xiaoShuWeiShu2 = (arg2+"").split(".")[1].length;
	}else{
		xiaoShuWeiShu2 = 0;
	}
	zeros1 = "";
	if(xiaoShuWeiShu1 == 0 && xiaoShuWeiShu2 == 0){
		return arg1 + arg2;
	}else{
		arg1 = arg1 + "";
		arg2 = arg2 + "";
		arg1 = arg1.replace(".", "");
		arg2 = arg2.replace(".", "");
		if(xiaoShuWeiShu1 > xiaoShuWeiShu2){
			for(var i631=0; i631<xiaoShuWeiShu1-xiaoShuWeiShu2; i631++){
				zeros1 = zeros1 + "0";
			}
			for(var i631=0; i631<xiaoShuWeiShu1; i631++){
				zeros2 = zeros2 + "0";
			}
			arg2 = arg2 + zeros1;
		}else if(xiaoShuWeiShu1 < xiaoShuWeiShu2){
			for(var i631=0; i631<xiaoShuWeiShu2-xiaoShuWeiShu1; i631++){
				zeros1 = zeros1 + "0";
			}
			for(var i631=0; i631<xiaoShuWeiShu2; i631++){
				zeros2 = zeros2 + "0";
			}
			arg1 = arg1 + zeros1;
		}else{
			for(var i631=0; i631<xiaoShuWeiShu1; i631++){
				zeros1 = zeros1 + "0";
				zeros2 = zeros2 + "0";
			}
		}
		arg11 = parseInt(arg1);
		arg21 = parseInt(arg2);
		
		return (arg11 + arg21) / parseInt("1" + zeros2);
	}
}

// This function is used to prevent the deviation for subtracting
// 此方法用于防止减法误差
function accSub(arg1, arg2) {
	var zeros1 = "";
	var zeros2 = "";
	var xiaoShuWeiShu1 = 0;
	var xiaoShuWeiShu2 = 0;
	var arg11 = 0;
	var arg21 = 0;
	if((arg1 + "").includes(".")){
		xiaoShuWeiShu1 = (arg1+"").split(".")[1].length;
	}else{
		xiaoShuWeiShu1 = 0;
	}
	if((arg2 + "").includes(".")){
		xiaoShuWeiShu2 = (arg2+"").split(".")[1].length;
	}else{
		xiaoShuWeiShu2 = 0;
	}
	if(xiaoShuWeiShu1 == 0 &amp;&amp; xiaoShuWeiShu2 == 0){
		return arg1 - arg2;
	}else{
		arg1 = arg1 + "";
		arg2 = arg2 + "";
		arg1 = arg1.replace(".", "");
		arg2 = arg2.replace(".", "");
		if(xiaoShuWeiShu1 > xiaoShuWeiShu2){
			for(var i631=0; i631<xiaoShuWeiShu1-xiaoShuWeiShu2; i631++){
				zeros1 = zeros1 + "0";
			}
			for(var i631=0; i631<xiaoShuWeiShu1; i631++){
				zeros2 = zeros2 + "0";
			}
			arg2 = arg2 + zeros1;
		}else if(xiaoShuWeiShu1 < xiaoShuWeiShu2){
			for(var i631=0; i631<xiaoShuWeiShu2-xiaoShuWeiShu1; i631++){
				zeros1 = zeros1 + "0";
			}
			for(var i631=0; i631<xiaoShuWeiShu2; i631++){
				zeros2 = zeros2 + "0";
			}
			arg1 = arg1 + zeros1;
		}else{
			for(var i631=0; i631<xiaoShuWeiShu1; i631++){
				zeros1 = zeros1 + "0";
			}
		}
		arg11 = parseInt(arg1);
		arg21 = parseInt(arg2);
		
		return (arg11 - arg21) / parseInt("1" + zeros2);
	}
}

// This function is used to prevent the deviation for multiplying
// 此方法用于防止乘法误差
function accMul(arg1, arg2) {
	var zeros1 = "";
	var xiaoShuWeiShu1 = 0;
	var xiaoShuWeiShu2 = 0;
	var arg11 = 0;
	var arg21 = 0;
	if((arg1 + "").includes(".")){
		xiaoShuWeiShu1 = (arg1+"").split(".")[1].length;
	}else{
		xiaoShuWeiShu1 = 0;
	}
	if((arg2 + "").includes(".")){
		xiaoShuWeiShu2 = (arg2+"").split(".")[1].length;
	}else{
		xiaoShuWeiShu2 = 0;
	}
	if(arg2 == 0){
		return 0;
	}else if(arg2 == 1){
		return arg1;
	}else if(xiaoShuWeiShu1 == 0 &amp;&amp; xiaoShuWeiShu2 == 0){
		return arg1 * arg2;
	}else{
		arg1 = arg1 + "";
		arg2 = arg2 + "";
		arg1 = arg1.replace(".", "");
		arg2 = arg2.replace(".", "");
		if(xiaoShuWeiShu1 > xiaoShuWeiShu2){
			for(var i631=0; i631<xiaoShuWeiShu1-xiaoShuWeiShu2; i631++){
				zeros1 = zeros1 + "0";
			}
			arg2 = arg2 + zeros1;
		}else if(xiaoShuWeiShu1 < xiaoShuWeiShu2){
			for(var i631=0; i631<xiaoShuWeiShu2-xiaoShuWeiShu1; i631++){
				zeros1 = zeros1 + "0";
			}
			arg1 = arg1 + zeros1;
		}else{
			for(var i631=0; i631<xiaoShuWeiShu1; i631++){
				zeros1 = zeros1 + "0";
			}
		}
		arg11 = parseInt(arg1);
		arg21 = parseInt(arg2);
		
		return arg11 * arg21 / parseInt("1" + zeros1 + zeros1);
	}
}

// This function is used to prevent the deviation for dividing
// 此方法用于防止除法误差
function accDiv(arg1, arg2) {
	var zeros1 = "";
	var xiaoShuWeiShu1 = 0;
	var xiaoShuWeiShu2 = 0;
	var arg11 = 0;
	var arg21 = 0;
	if((arg1 + "").includes(".")){
		xiaoShuWeiShu1 = (arg1+"").split(".")[1].length;
	}else{
		xiaoShuWeiShu1 = 0;
	}
	if((arg2 + "").includes(".")){
		xiaoShuWeiShu2 = (arg2+"").split(".")[1].length;
	}else{
		xiaoShuWeiShu2 = 0;
	}
	if(arg2 == 0){
		if(arg1 > 0){
			return Infinity;
		}else if(arg < 0){
			return -Infinity;
		}else{
			return NaN;
		}
	}else if(arg2 == 1){
		return arg1;
	}else if(xiaoShuWeiShu1 == 0 &amp;&amp; xiaoShuWeiShu2 == 0){
		return arg1 / arg2;
	}else{
		arg1 = arg1 + "";
		arg2 = arg2 + "";
		arg1 = arg1.replace(".", "");
		arg2 = arg2.replace(".", "");
		if(xiaoShuWeiShu1 > xiaoShuWeiShu2){
			for(var i631=0; i631<xiaoShuWeiShu1-xiaoShuWeiShu2; i631++){
				zeros1 = zeros1 + "0";
			}
			arg2 = arg2 + zeros1;
		}else if(xiaoShuWeiShu1 < xiaoShuWeiShu2){
			for(var i631=0; i631<xiaoShuWeiShu2-xiaoShuWeiShu1; i631++){
				zeros1 = zeros1 + "0";
			}
			arg1 = arg1 + zeros1;
		}else{
			for(var i631=0; i631<xiaoShuWeiShu1; i631++){
				zeros1 = zeros1 + "0";
			}
		}
		arg11 = parseInt(arg1);
		arg21 = parseInt(arg2);
		
		return arg11 / arg21;
	}
}

如何利用我的解决方案来更准确地计算?

调用方法accAdd(a, b);、accSub(a, b);、accMul(a, b);或accDiv(a, b);,将a和b替换为你的数字。

// Add Accurately
// 准确地计算加法
var addResult = accAdd(a, b); // a + b
// Subtract Accurately
// 准确地计算减法
var subtractResult = accSub(a, b); // a - b
// Multiply Accurately
// 准确地计算乘法
var multiplyResult = accMul(a, b); // a * b
// Divide Accurately
// 准确地计算除法
var divideResult = accMul(a, b); // a / b

例如19.6除以10

// Add my solution code above here first.
// 先在此处添加上面的解决方案代码
var a = 19.6;
var b = 10;
var c = accDiv(a, b);
alert(a + " divides " + b + " is equal to " + c);

如果你有编程问题,请告诉我

我有很强的计算机编程能力。如果你不能自己解决你的JavaScript编程问题,比如说这个问题,你可以告诉我。我会尽我所能解决你的问题。

现在你可以使用编程语言跟我交流或聊天,联系我或向我发送消息时可以使用编程语言。

联系我

总结

这个代码是我的想法,你可以免费使用。我希望我的解决方案代码可以帮助到你,并解决你的问题。

I am a Chinese student, this is my personal website and blog. I have strong programming ability, but this can’t be meant there is no bug in my programs. If you have suggestions or found any bugs in this code, comment your suggestions below or contact me or report bugs of my programs anytime, I will answer it soon.


非常感谢你的阅读!

相关的文章
我2020年暑假的Python编程旅程

Several days ago, my Python programming journey in 2020 summer vacation is arrived at the terminal, in which I have 阅读更多

I Got an Outstanding Award in a Programming Competition
Outstanding Award in JS Programming Competition 2020

Recently, I got an outstanding award in a programming competition that is hosted by my programming class TCTM. It is 阅读更多

好消息!我被编程辅导班重点介绍了!

Yesterday is a Chinese 1024 Programmer's Festival, October 24, 2019, and I heard good news: I have been featured by 阅读更多

发表评论

电子邮件地址不会被公开。 必填项已用*标注