точность аргумента в pow() C

Вот код C;

#include<stdio.h>
#include<math.h>
int main()
{
    double n=10.0;
    double automatic = pow(10.0,log10(n)-log10(5.0));
    printf("%.9lf\n",log10(n)-log10(5.0));
    printf("%.9lf\n",pow(10.0,0.30102996));
    double manual = pow(10.0,0.30102996);
    printf("%.9lf %lf\n",automatic, floor(automatic));
    printf("%.9lf %lf\n",manual,floor(manual));
    return 0;
}

Выход:

0.301029996
1.999999836
2.000000000 1.000000
1.999999836 1.000000

Из вывода я могу сделать вывод, что в pow (x, y) y округляется до 6 цифр, потому что его подпись имеет вид pow (double x, double y), так что 0,301029996 становится 0,301030, и поэтому значение Automatic равно 2,000000000, иначе это было бы то же, что ручной.

Мои вопросы:

  1. Верен ли мой вывод?
  2. Если ответ на первый вопрос верен, то как мы можем обойти это округление, чтобы получить более точные результаты?

person Bharat Kul Ratan    schedule 12.08.2012    source источник
comment
Я использую gcc, поэтому мне нужны методы, как это сделать в gcc.   -  person Bharat Kul Ratan    schedule 12.08.2012


Ответы (1)


pow не округляется до 6 цифр. Он использует двойную точность, которая для двойной точности IEEE составляет 52 бита мантиссы (примерно 15 знаков после запятой). Это может быть или не быть точным до последней цифры с такой точностью, но обычно это близко.

Точное значение журнала по основанию 10, равное 2, близко к 0.301029995663981195213738894724 (источник: Wolfram Alpha). Это иррациональное число, поэтому его нельзя точно представить ни в какой системе счисления (десятичной или двоичной).

Ваши результаты показывают, что log10(n)-log10(5.0) вернуло значение, которое ближе к точному математическому логарифмическому основанию 10, равному 2, чем 0.30102996. Причина, по которой вы получили 1.999999836, заключается в том, что вы вручную сделали свое значение менее точным, когда заменили его на 0.30102996. Кстати, это не округленное значение - посчитайте девятки.

Ваш вызов pow(10.0,log10(n)-log10(5.0)) вернул результат, который немного меньше, чем 2 (как показывает floor), но достаточно близок, чтобы округлить до 2 в 9 разрядах. Вы не станете лучше, чем это, используя двойной тип.

Так что я действительно не знаю, что вы подразумеваете под «избегать округления». Если вы не хотите, чтобы значение было менее точным, не округляйте его вручную до 9 знаков и, конечно же, не пропускайте ни одной цифры при копировании ;-)

person Steve Jessop    schedule 12.08.2012
comment
Японял твою точку зрения; так что это означает, что значение Automatic равно 2.000000000 из-за printf. На самом деле это не 2, а 1,99999... - person Bharat Kul Ratan; 12.08.2012
comment
@tendua: да, это где-то от 1,9999999995 до 2. Если вы напечатаете 2.0 - pow(10.0,log10(n)-log10(5.0)), вы должны увидеть величину ошибки, хотя я думаю, что возможно, вы получите 0. Зависит от того, позволяет ли компилятор FPU использовать лучше, чем- двойная точность для промежуточных результатов. - person Steve Jessop; 12.08.2012