为什么Math.sqrt()在java中输出错误的值?
long mynum = Long.parseLong("7660142319573120");
long ans = (long)Math.sqrt(mynum) // output = 87522239
long ans_ans = ans * ans;
在这种情况下,我得到了ans_ans> mynum,它应该是< = mynum。为什么这样的行为我也尝试过使用节点js。结果也是一样的。为什么Math.sqrt()在java中输出错误的值?
答案是:四舍五入。 (Long)Math.sqrt(7660142319573120)
的结果为87522239
,但数学结果为87522238,999999994287166259537761...
。 如果你乘以ans
的值,为了存储为一个整数,这个值被舍入,你会得到比乘以精确结果更大的数字。
如果是四舍五入,Math.sqrt(15)的答案应该是4,因为它是3.872983346207417 –
Math.sqrt
操作上double
S,不long
S,SO mynum
被转换到一个double
第一。这是一个64位浮点数,它有“精度15-17位十进制数”(Wikipedia)。
您的输入号码有16位数字,所以您可能会失去输入精度。你也可能会失去输出的精度。
如果您确实需要long
数字的整数平方根或通常数字太大而不能精确表示为double
,请查看integer square root算法。
您也可以使用Guava图书馆的LongMath.sqrt()
。
您打电话给Math.sqrt
很长。正如JavaDoc指出的那样,它返回一个“正确舍入的值”。
由于您的平方根不是非逗号值(87522238,999999994
),因此您的结果会四舍五入到您的输出87522239
。
之后,数值的平方直观地大于mynum
,因为您乘数大于根!
如果是四舍五入,Math.sqrt(15)的答案应该是4,因为它是3.872983346207417 –
@AbhilashMandaliya是的,没错,Math.sqrt()的结果是双精度的,但在你的例子中,它被转换为long:(long)Math.sqrt(mynum),所以它会自动舍入。尝试Math.sqrt(15)和(long)Math.sqrt(15)来看看区别 – RetteMich
它只有在@IfOnly在下面提到时才有3 –
double ans = (double)Math.sqrt(15);
System.out.println("Double : " + ans);
double ans_ans = ans * ans;
System.out.println("Double : " + ans_ans);
long ans1 = (long)Math.sqrt(15);
System.out.println("Long : " + ans1);
long ans_ans1 = ans1 * ans1;
System.out.println("Long : " + ans_ans1);
结果:
Double : 3.872983346207417
Double : 15.000000000000002
Long : 3
Long : 9
我希望这个说清楚。
干杯!
您不需要长型,所有数字都可以在double
中表示,而Math.sqrt
先转换为double,然后通过FPU指令(在标准PC上)计算平方根。
这种情况发生时对数字b=a^2-1
其中a
是
67108865 <= a <= 94906265
的b
平方根具有级数展开的范围内开始
a-1/(2*a)-1/(8*a^2)+...
的整数。如果相对误差1/(2*a^2)
下降到低于该机器epsilon,最接近double
号码是a
。
在另一方面,对于这一招工作的人需要的是a*a-1.0
是double
精确表示,这给条件
1/(2*a^2) <mu=2^(-53) < 1/(a^2)
或
2^52 < a^2 < 2^53
2^26+1=67108865 <= a <= floor(sqrt(2)*2^26)=94906265
你可以写'长myNum的= 7660142319573120L; '而不是使用parseLong。与问题无关,只是一般性评论。 –
非常感谢您的建议 –