Java与罪恶和托拉第斯的奇怪行为

Java与罪恶和托拉第斯的奇怪行为,java,Java,我被赋予了使用java生成Sin表的任务,但是对于输入的某些值,我似乎得到了一些非常奇怪的结果。我正在使用下面的 System.out.println("| sin(" + currentPoint + ") = " + Math.sin(Math.toRadians(currentPoint))); 其中(int)currentPoint是以度为单位的值(如90) 这些结果我觉得很奇怪 | sin(360) = -2.4492935982947064E-16 | sin(180) = 1.2

我被赋予了使用java生成Sin表的任务,但是对于输入的某些值,我似乎得到了一些非常奇怪的结果。我正在使用下面的

System.out.println("| sin(" + currentPoint + ") = " + Math.sin(Math.toRadians(currentPoint)));
其中(int)currentPoint是以度为单位的值(如90)

这些结果我觉得很奇怪

| sin(360) = -2.4492935982947064E-16
| sin(180) = 1.2246467991473532E-16
| sin(150) = 0.49999999999999994
| sin(120) = 0.8660254037844387
期待

sin(360) = 0
sin(180) = 0
sin(150) = 0.5
sin(120) = 0.866025404

我遗漏了什么吗?

如果您的代码是
System.out.println(“| sin”(+currentPoint+”)=“+Math.sin(currentPoint))您可能期望这样:

sin(360) = 0.958915723 sin(180) = -0.801152636 sin(150) = -0.71487643 sin(120) = 0.580611184 sin(360)=0.958915723 sin(180)=-0.80152636 sin(150)=-0.71487643 sin(120)=0.580611184 换句话说,360弧度的正弦为0.9589,但360度的正弦为0

编辑:
您看到意外结果的原因只是因为计算中缺乏精确性。如果您只是对结果进行格式化,使其小数位数更少,则四舍五入即可。这样做:

System.out.printf(“|sin(%d)=%.7f\n”,currentPoint,Math.sin(Math.toRadians(currentPoint))


然后你会得到更接近你期望的结果。

上面的海报是正确的。您期望的正确值为:

正弦(360度)=0 正弦(180度)=0 正弦(150度)=0.5 正弦(120度)=.866

代码正在返回正确答案。他们只需要四舍五入。试试这个:

System.out.printf("%s%.3f","| sin(" + currentPoint + ") = ", (Math.sin(Math.toRadians(currentPoint))));
如果要提高或降低十进制精度,可以将.3f值更改为不同的数字

出于某种原因,它将360的sin显示为-0.00。我相信有一个更优雅的解决方案,但这应该是可行的


编辑:被秒击败。使用我上面的代码,它更容易阅读。

下面是该方法的API描述。注意asterix中的部分。 我敢打赌,您的预期结果与您得到的结果之间的差异是浮点计算或舍入问题的缺陷

公共静态双sin(双a)

与论点相同的符号

A result must be within 1 **ulp** of the correctly rounded result. Results
必须是半单调的

Parameters:
    a - an angle, in radians. 
Returns:
    the sine of the argument.

在处理浮点数时,寻找精确答案并不适用于所有值。看看 . 您希望您的测试在某个增量内与您的期望相等。请注意,您得到的答案非常接近。它以比特的形式表达价值,这让你心痛不已

从链接:

将无限多个实数压缩成有限位数需要近似表示。尽管有无限多个整数,但在大多数程序中,整数计算的结果可以存储在32位中。相反,给定任何固定的位数,大多数实数计算将产生无法用那么多位数精确表示的量。因此,浮点计算的结果必须经常四舍五入,以适应其有限表示形式。这种舍入误差是浮点计算的特征


还要注意,Math.PI是一个双精度值,它不是PI,只是PI的近似值,而Math.sin(Math.PI)给出的双精度值与sin(Math.PI)的实际数学值最接近。

您的结果是正确的。。。要获得近似值,请尝试此

    result=Math.sin(Math.toRadians(value));
    result=format(result);


    private double format(double value) {
            return (double)Math.round(value * 1000000) / 1000000; //you can change this to round up the value(for two position use 100...)
        }

如上所述,这不是一个错误,只是计算机浮点运算的近似值

要获得预期的答案,因为sin()和cos()介于-1、0和+1之间,请尝试将其四舍五入到所需的精度,然后减去1

x = round15(Math.sin(toRad(angle))+1)-1;
其中定义了round15

public double round15(double x){
    DecimalFormat twoDForm = new DecimalFormat("0.##############E0");
    String str = twoDForm.format(x);
    return Double.valueOf(str);
}

它适合我,希望未来的读者喜欢。

你必须像这样将角度转换成弧度


根据,
sin(360度)
实际上是
0
,结果必须是1。你确定你的意思是正弦吗?你的预期结果将这些值解释为弧度,而在你的程序中,你将它们视为度数。你的代码是正确的,预期是错误的。Sin 180 degrees=Sin(PI)=
Sin(PI)=1.2246467991473532E-16
(根据java)。CodeSystem.out.println(“Sin(PI)=”+Math.Sin(Math.PI))我没有这两个选项..?佩兹:你的结果是正确的,只是格式不好。
public double round15(double x){
    DecimalFormat twoDForm = new DecimalFormat("0.##############E0");
    String str = twoDForm.format(x);
    return Double.valueOf(str);
}