简体   繁体   English

Sin和ToRadians的Java奇怪行为

[英]Java Strange Behavior with Sin and ToRadians

I have been given the task of using java to produce a Sin table, however I seem to get some very weird results for some values of the input. 我已经被赋予了使用java来生成Sin表的任务,但是对于某些输入值,我似乎得到了一些非常奇怪的结果。 I am using the below 我使用下面的

System.out.println("| sin(" + currentPoint + ") = " + Math.sin(Math.toRadians(currentPoint)));

Where (int) currentPoint is a value in degrees (eg 90) Where(int)currentPoint是一个以为单位的值(例如90)

These are results I find weird 这些结果我觉得很奇怪

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

Expecting 期待

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

Am I missing something? 我错过了什么吗?

You're dealing with floating point numbers, looking for exact answers isn't going to work for all values. 您正在处理浮点数,寻找确切的答案对所有值都不起作用。 Take a look at What Every Computer Scientist Should Know About Floating-Point Arithmetic . 看看每个计算机科学家应该知道的关于浮点算术的内容 You want your tests to be equivalent to your expectations within some delta. 您希望您的测试与某些增量中的预期相当。 Note that the answers you're getting are pretty close. 请注意,您得到的答案非常接近。 It's expressing values in bits that's biting you. 它以咬你的比特来表达价值。

From the link: 从链接:

Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation. 将无限多个实数压缩成有限数量的比特需要近似表示。 Although there are infinitely many integers, in most programs the result of integer computations can be stored in 32 bits. 尽管存在无限多个整数,但在大多数程序中,整数计算的结果可以以32位存储。 In contrast, given any fixed number of bits, most calculations with real numbers will produce quantities that cannot be exactly represented using that many bits. 相反,给定任何固定数量的位,大多数具有实数的计算将产生无法使用那么多位精确表示的量。 Therefore the result of a floating-point calculation must often be rounded in order to fit back into its finite representation. 因此,浮点计算的结果通常必须舍入,以便适应其有限表示。 This rounding error is the characteristic feature of floating-point computation. 该舍入误差是浮点计算的特征。

As mentioned above it is not an error, just the aproximation of computer's floating point arithmetic. 如上所述,它不是错误,只是计算机浮点运算的近似。

To get the expected answer, as sin() & cos() are between -1, 0 , +1, try to add 1 round it to the accurancy needed and substract 1. 为了获得预期的答案,因为sin()和cos()在-1,0,+ 1之间,尝试将1轮加到需要的精度并减去1。

x = round15(Math.sin(toRad(angle))+1)-1;

where round15 is defined 其中round15定义

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

It works for me, hope future readers like it. 它适合我,希望未来的读者喜欢它。

If your code was System.out.println("| sin(" + currentPoint + ") = " + Math.sin(currentPoint)); 如果您的代码是System.out.println("| sin(" + currentPoint + ") = " + Math.sin(currentPoint)); you would expect this: 你会期待这个:

sin(360) = 0.958915723 
sin(180) = -0.801152636 
sin(150) = -0.71487643 
sin(120) = 0.580611184

In other words, the sine of 360 radians is 0.9589, but the sine of 360 degrees is 0. 换句话说,360弧度的正弦为0.9589,但360度的正弦 0。

EDIT: 编辑:
The reason you're seeing unexpected results is just due to lack of precision in the calculations. 您看到意外结果的原因仅仅是由于计算精度不高。 If you just format the results so they have fewer decimal places, the rounding will take care of it. 如果您只是格式化结果,以便它们具有更少的小数位,则舍入将处理它。 Do something like this: 做这样的事情:

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

Then you will get results closer to what you expect. 然后你会得到更接近你期望的结果。

Your results are correct ... for approximation try this... 你的结果是正确的...近似试试这个......

    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...)
        }

The posters above are right. 上面的海报是对的。 The correct values you are expecting are: 您期望的正确值是:

Sin(360 degrees) = 0 Sin(180 degrees) = 0 Sin(150 degrees) = .5 Sin(120 degrees) = .866 Sin(360度)= 0 Sin(180度)= 0 Sin(150度)= .5 Sin(120度)= .866

The code is returning the correct answers. 代码返回正确的答案。 They just need to be rounded. 他们只需要四舍五入。 Try this: 试试这个:

System.out.printf("%s%.3f","| sin(" + currentPoint + ") = ", (Math.sin(Math.toRadians(currentPoint))));

You can change the .3f value to different numbers if you want to improve or reduce decimal precision. 如果要提高或降低小数精度,可以将.3f值更改为不同的数字。

For some reason it displays the sin of 360 to be -0.00. 由于某种原因,它显示360的罪为-0.00。 I am sure there is a more elegant solution, but this should work. 我确信有一个更优雅的解决方案,但这应该工作。

EDIT: Beaten by seconds. 编辑:秒数击败。 Use the code above mine, it is easier to read. 使用我上面的代码,它更容易阅读。

另请注意,Math.PI是一个双精度值,不是PI,而只是PI的近似值,Math.sin(Math.PI)为您提供了与sin的实际数学值最接近的double值(Math .PI)。

You must convert the angle into radians like this 您必须将角度转换为像这样的弧度

Math.sin(Math.toRadians(90)) and the result must be 1 Math.sin(Math.toRadians(90)),结果必须为1

Below is the API description of the Math.sin method. 以下是Math.sin方法的API描述。 Note the part in asterix. 注意星号中的部分。 I would bet that the difference between your expected results and the once you get are defects of floatpoint calculation or rounding problems. 我敢打赌,你的预期结果和你得到的结果之间的差异是浮点数计算或舍入问题的缺陷。

sin

public static double sin(double a) public static double sin(double a)

 Returns the trigonometric sine of an angle. Special cases: * If the argument is NaN or an infinity, then the result is NaN. * If the argument is zero, then the result is a zero with the 

same sign as the argument. 与参数相同的符号。

 A result must be within 1 **ulp** of the correctly rounded result. Results 

must be semi-monotonic. 必须是半单调的。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM