简体   繁体   English

C中是否有任何精确的三角函数?

[英]Are there any accurate trigonometric functions in C?

I am working with some programming problems which require the use of trigonometric functions. 我正在处理一些需要使用三角函数的编程问题。 Unfortunately, the functions in the math.h library seem to be inaccurate. 不幸的是, math.h库中的函数似乎不准确。 Here is an example: 这是一个例子:

#include <stdio.h>
#include <math.h>    
int main() {
  double a, b, c, d;
  a = sin(0.0);
  b = sin(90.0);
  c = cos(0.0);
  d = cos(90.0);
  printf("A = %lf\nB = %lf\nC = %lf\nD = %lf\n", a, b, c, d);
  return (0);
}

OUTPUT: 输出:

A = 0.000000
B = 0.893997
C = 1.000000
D = -0.448074

So is there any way to make these functions accurate? 那么有什么方法可以使这些功能准确无误? Or do I have to make my own functions using series? 还是我必须使用系列来制作自己的函数?

I googled and so far could not find any way to make the functions accurate but using series. 我用谷歌搜索,到目前为止,找不到任何使函数准确的方法,但是使用了序列。

Functions sin() and cos() expect radians. 函数sin()cos()期望弧度。 They are usually “faithful”, that is, they produce results within 1 ULP of the mathematical result, at least for arguments up to a couple of thousands. 它们通常是“忠实的”,也就是说,它们产生的结果在数学结果的1 ULP之内,至少对于成千上万的论点而言。

#include <stdio.h>
#include <math.h>    
int main() {
  double a, b, c, d;
  a = sin(0.0);
  b = sin(0.5 * 3.1415926535897932);
  c = cos(0.0);
  d = cos(0.5 * 3.1415926535897932);
  printf("A = %lf\nB = %lf\nC = %lf\nD = %lf\n", a, b, c, d);
  return (0);
}

A = 0.000000
B = 1.000000
C = 1.000000
D = 0.000000

EDITED TO ADD: 编辑添加:

Camilo Martinez points out that “Unit in the Last Place” is a bit of a specialized notion. 卡米洛·马丁内斯(Camilo Martinez)指出,“最后的单位”有点专门的概念。 In simpler terms, there are a finite number of double values, denser around zero: 用更简单的术语来说,存在有限数量的double精度值,在零附近更密集:

++-+-+-+---+---+-------+---------------+-------------------------------+--

The exact trigonometric value you are computing almost always falls in-between two of these double s (the only exceptions are sin(0.0) = 0.0 and cos(0.0) = 1.0 ): 您正在计算的精确三角值几乎总是介于这两个double值之间(唯一的例外是sin(0.0) = 0.0cos(0.0) = 1.0 ):

++-+-+-+---+---+-------+---------------+-------------------------------+--
                       |    ^          |
                     lower  |       upper
                     double |       double
                            |
                   exact (mathematical) result

Most libraries provide functions that will, in normal circumstances, give you the double immediately above the exact result or immediately below the mathematical result. 大多数库提供的功能在正常情况下会在精确结果的正上方或数学结果的正下方提供double精度值。 This is pretty good considering the difficulty of the question. 考虑到问题的难度,这很好。

Some libraries provide functions that will give you the double nearest to the exact result, for all inputs (even 1E21 ). 一些库提供的函数将为您提供所有输入(甚至1E21最接近精确结果的双1E21 This is an astounding result. 这是一个惊人的结果。 Until relatively recently this could only be obtained at the cost of expensive computations, but nowadays, you can even obtain this sort of result nearly as fast as with the less accurate functions of the past. 直到最近,这只能以昂贵的计算为代价来获得,但是如今,您甚至可以获得与过去不太精确的函数一样快的结果。

Finally, sometimes you are not even applying sin() or cos() to the number you would like to, but only to its nearest double approximation. 最后,有时您甚至没有将sin()cos()应用于您想要的数字,而只是将其应用于最接近的double精度近似值。 This is the case in your example once fixed: you would like to apply sin() and cos() to π/2, but you can't, because π/2 is not representable as a double . 固定后的示例就是这种情况:您想将sin()cos()应用于π/ 2,但不能这样做,因为π/ 2不能表示为double You have to apply them to the nearest available double instead (this is what the fixed program does). 您必须将它们应用于最近的可用double精度数(这是固定程序的作用)。

Such inaccuracies can compound . 这样的错误会加剧 The process by which they do have given floating-point computations a bad reputation, but actually, the way floating-point inaccuracies compound is very predictable and can be taken into account when writing programs that use floating-point. 他们的过程确实给浮点计算带来了不好的声誉,但是实际上,浮点不准确复合的方式是非常可预测的,在编写使用浮点的程序时可以考虑到这一点。

If you really need to work in degrees and have correct results, the standard trigonometric functions are not sufficient. 如果您确实需要按度数工作并获得正确的结果,则标准三角函数是不够的。 For instance, cos(90*M_PI/180) will not yield 0.0 . 例如, cos(90*M_PI/180)不会产生0.0 The error is probably less than 1ulp except when the correct result is zero (or maybe very close to zero), so you might just decide to be happy with using them anyway. 该错误可能小于1ulp,除非正确的结果为零(或者可能非常接近零),所以您可能仍然决定对使用它们感到满意。 To get better results, you'd need to adapt the existing algorithms to work in degrees (in some ways this will be easier since argument-reduction, one of the hardest parts of implementing the trig functions, is trivial in degrees) and do some numerical analysis to ensure you're within the error bounds you want. 为了获得更好的结果,您需要使现有算法适应于度数的工作方式(在某些方面,这将变得更加容易,因为实参归约是实现trig函数的最难部分之一,在度数上是微不足道的),并且需要做一些数值分析,以确保您在所需的误差范围内。

A quick fix-up for working in degrees would be to just special-case multiples of 30 (where all the exact results fall) and call cos(x*M_PI/180) , etc. for all other values. 快速修正以度为单位的工作将是30的特殊情况下的倍数(所有精确结果均落在其中cos(x*M_PI/180) ,并对所有其他值调用cos(x*M_PI/180)等。 This won't be perfect but at least it will avoid introducing messy inexactness at points that should be exact. 这不是完美的,但至少它将避免在应该精确的点上引入混乱的不精确性。

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

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