Значения с плавающей запятой с помощью sin () и sinf ()

Почему я получаю то же значение от sin (x) и sinf (x), что и в (8) и (9) ниже? Почему я получаю разные значения [x — sinf (x)] из двух разных реализаций (2) и (3) ниже? Почему (6) дает тот же результат, что и (5)?

Я использую g ++ (Ubuntu / Linaro 4.6.3-1ubuntu5) 4.6.3. Я использовал -O0, чтобы отключить оптимизацию.

Предыстория: я обнаружил ошибку в моей программе, где я должен использовать float по всей программе, потому что она будет перенесена во встроенную систему. Тем не менее, в настоящее время я отлаживаю Ubuntu на своем компьютере только потому, что это удобно. Я обнаружил, что операция типа (x-s) вызывала неточность, когда x был маленьким. Это заставило меня думать, что это должно быть связано с потерей значащих цифр в результате катастрофической отмены. Однако, когда я заменил переменную s на sinf (x), проблема неточности не возникла (как видно из (2) против (3)). Я мог бы предположить, что sinf () может быть реализован так же, как sin (). Если так, то почему явное приведение к float не имеет эффекта, как в (4) и (5). Теперь я озадачен.

int main()
{
unsigned long int xx(0x3d65c2f2);
float x(*reinterpret_cast<float*>(&xx));
float s(sinf(x));

printf("( 1) x                         = %.10e\n", x);
printf("( 2) x - s                     = %.10e\n", x-s);
printf("( 3) x - sinf(x)               = %.10e\n", x-sinf(x)); // Why is it different from (2)?
printf("( 4) x - float(sinf(x))        = %.10e\n", x-float(sinf(x))); // Compare with (3). Why casting has no effect?
printf("( 5) float(x) - float(sinf(x)) = %.10e\n", float(x)-float(sinf(x))); // Compare with (3). Why casting has no effect?
printf("( 6) x - sin(x)                = %.10e\n", x - sin(x));

printf("( 7) s                         = %.10e\n", s);
printf("( 8) sinf(x)                   = %.10e\n", sinf(x));
printf("( 9) sin(x)                    = %.10e\n", sin(x)); // Compare with (8). Is sinf() identical to sin()?
printf("(10) float(sinf(x))            = %.10e\n", float(sinf(x))); // Compare with (8). Why casting has no effect?

double s_df(sinf(x));
double s_dd(sin(x));
float s_fd(sin(x));
float s_ff(sinf(x));
printf("(20) s_df               = %.10e\n", s_df);
printf("(21) s_dd               = %.10e\n", s_dd); // Compare with (20). Is sinf() identical to sin()?
printf("(22) s_fd               = %.10e\n", s_fd);
printf("(23) s_ff               = %.10e\n", s_ff);

return 0;
}

Вот вывод:

$ make && ./main
g++ main.cc -Wall  -c -o main.o -O0
g++ -o main main.o
( 1) x                         = 5.6094117463e-02
( 2) x - s                     = 2.9411166906e-05
( 3) x - sinf(x)               = 2.9412529899e-05
( 4) x - float(sinf(x))        = 2.9412529899e-05
( 5) float(x) - float(sinf(x)) = 2.9412529899e-05
( 6) x - sin(x)                = 2.9412529899e-05
( 7) s                         = 5.6064706296e-02
( 8) sinf(x)                   = 5.6064704933e-02
( 9) sin(x)                    = 5.6064704933e-02
(10) float(sinf(x))            = 5.6064704933e-02
(20) s_df               = 5.6064704933e-02
(21) s_dd               = 5.6064704933e-02
(22) s_fd               = 5.6064706296e-02
(23) s_ff               = 5.6064706296e-02

1

Решение

В C ++ sin имеет перегрузку float sin(float f), И разрешение перегрузки делается на типе аргумента, а не на типе возврата. Чтобы заставить использование double sin(double d) вам нужно привести аргумент: sin(static_cast<double>(x)),

(2) против (3): стандарт FP позволяет реализациям хранить промежуточные результаты с большей точностью, чем конечный результат. Так что ценность s не должны быть точно такими же, как промежуточный результат для sin(f) в (3).

Многое из этого зависит от вашего компилятора, настроек компилятора и аппаратного обеспечения. Например, если я запускаю ваш код в моей системе, я получаю:

( 1) x                         = 5.6094117463e-02
( 2) x - s                     = 2.9411166906e-05
( 3) x - sinf(x)               = 2.9411166906e-05
( 4) x - float(sinf(x))        = 2.9411166906e-05
( 5) float(x) - float(sinf(x)) = 2.9411166906e-05
( 6) x - sin(x)                = 2.9412529899e-05
( 7) s                         = 5.6064706296e-02
( 8) sinf(x)                   = 5.6064706296e-02
( 9) sin(x)                    = 5.6064704933e-02
(10) float(sinf(x))            = 5.6064706296e-02
(20) s_df               = 5.6064706296e-02
(21) s_dd               = 5.6064704933e-02
(22) s_fd               = 5.6064706296e-02
(23) s_ff               = 5.6064706296e-02
3

Другие решения


По вопросам рекламы [email protected]