如何提高iOS上std :: sin函数的精度

时间:2019-03-01 17:44:07

标签: c++ ios precision

我有一个跨平台的应用程序,这是一个音频应用程序,因此使用了很多正弦波以及std::sin()和其他测角功能。

我注意到,特别是在iOS平台上,std::sin()的精度非常差。我写了以下测试:

void TestSineZeroCrossings()
{
   const static float kTwoPi = 6.28318530718f;
   const static float epsilon = 1e-5f;

   for (int ii = 0; ii < 10000; ++ii)
   {
       const float difference = std::abs(std::sin(kTwoPi * static_cast<float>(ii)));
       if (difference >  epsilon)
          printf("Zero crossing fail, difference: %f\n", difference);
   }
}

在Windows和MaxOSX上通过(即没有打印输出),但是在iOS上几乎每次迭代都失败。实际上,只有使用epsilon > 0.004f才能成功。这会在我的应用程序中产生明显的可听噪声。

有没有办法告诉编译器使用更好的实现,而不是有损的?

3 个答案:

答案 0 :(得分:2)

我认为实施非常准确。

您的实际问题是kTwoPi * static_cast<float>(ii)被舍入到下一个float。例如,对于ii=10000,该值为(如果我没有误算的话):62831.8515625 如果从精确的数学运算中减去10000*2*pi,您将得到大约:-0.001509...并且该值的正弦近似相同(而不是0)。它“相对”接近零,但与您想要的10e-6“准确性”相距甚远。

如果您想获得sin(x*pi)的更准确值,请查看boost::math::sin_pihttps://www.boost.org/doc/libs/1_69_0/libs/math/doc/html/math_toolkit/powers/sin_pi.html

答案 1 :(得分:0)

如果要提高精度,请使用doublelong double而不是float

例如,

替换

   const static float kTwoPi = 6.28318530718f;
   const static float epsilon = 10e-6f;

使用

   const static double kTwoPi = 6.28318530718;
   const static double epsilon = 10e-6;

const float difference = std::abs(std::sin(kTwoPi * static_cast<float>(ii)));

使用

const double difference = std::abs(std::sin(kTwoPi * ii));

答案 2 :(得分:0)

冒着重复的危险,您的问题显然是使用float而不是double或long double。

您可以通过

进行验证
cout << kTwoPi << endl ;

并查看打印出多少位数字,以及它们与原始值的比较。

  

const静态浮点数kTwoPi = 6.28318530718f;

大致等于

const static float kTwoPi = 6.283185 ;
在许多(大多数?)系统上

对于单个精度值,您的增量太小了。浮点数由于通常缺乏精度而对大多数应用程序无用。