Точность pow(x, 1.0)
От: McSeem2 США http://www.antigrain.com
Дата: 25.06.04 19:11
Оценка:
Есть такой код:

#include <math.h>
#include <stdio.h>

void main()
{
   int i;
   for(i = 0; i < 256; i++)
   {
      int j = int(pow(double(i) / 255.0, 1.0) * 255.0);
      double v = pow(double(i) / 255.0, 1.0) * 255.0;
      if(j != i) printf("%3d %3d %20.16f\n", i, j, v);
   }
}


В VC 6.0 при компиляции "cl a.cpp" работает нормально (ничего не печатает). С опцией /O2 выдает это:
33 32 32.9999999999999930
37 36 36.9999999999999930
41 40 40.9999999999999930
45 44 44.9999999999999930
49 48 48.9999999999999930
53 52 52.9999999999999930
57 56 56.9999999999999930
61 60 60.9999999999999930
66 65 65.9999999999999860
74 73 73.9999999999999860
82 81 81.9999999999999860
90 89 89.9999999999999860
98 97 97.9999999999999860
106 105 105.9999999999999900
114 113 113.9999999999999900
122 121 121.9999999999999900
132 131 131.9999999999999700
148 147 147.9999999999999700
164 163 163.9999999999999700
180 179 179.9999999999999700
196 195 195.9999999999999700
212 211 211.9999999999999700
228 227 227.9999999999999700
244 243 243.9999999999999700


g++ v 2.95.3-5 еще хуже:
1 0 1.0000000000000000
2 1 2.0000000000000000
3 2 3.0000000000000000
4 3 4.0000000000000000
5 4 5.0000000000000000
6 5 6.0000000000000000
7 6 7.0000000000000000
8 7 8.0000000000000000
9 8 9.0000000000000000
10 9 10.0000000000000000
11 10 11.0000000000000000
12 11 12.0000000000000000
13 12 13.0000000000000000
14 13 14.0000000000000000
15 14 15.0000000000000000
16 15 16.0000000000000000
17 16 17.0000000000000000
18 17 18.0000000000000000
19 18 19.0000000000000000
20 19 20.0000000000000000
. . .и т.д.

Потестируйте пожалуйста на разных компиляторах.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re: Точность pow(x, 1.0)
От: _AK_ Россия  
Дата: 25.06.04 21:33
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Есть такой код:


MS>
MS>#include <math.h>
MS>#include <stdio.h>

MS>void main()
MS>{
MS>   int i;
MS>   for(i = 0; i < 256; i++)
MS>   {
MS>      int j = int(pow(double(i) / 255.0, 1.0) * 255.0);
MS>      double v = pow(double(i) / 255.0, 1.0) * 255.0;
MS>      if(j != i) printf("%3d %3d %20.16f\n", i, j, v);
MS>   }
MS>}
MS>


MS>В VC 6.0 при компиляции "cl a.cpp" работает нормально (ничего не печатает). С опцией /O2 выдает это:

MS> 33 32 32.9999999999999930
MS> 37 36 36.9999999999999930
MS> 41 40 40.9999999999999930
MS> 45 44 44.9999999999999930
MS> 49 48 48.9999999999999930
MS> 53 52 52.9999999999999930
MS> 57 56 56.9999999999999930
MS> 61 60 60.9999999999999930
MS> 66 65 65.9999999999999860
MS> 74 73 73.9999999999999860
MS> 82 81 81.9999999999999860
MS> 90 89 89.9999999999999860
MS> 98 97 97.9999999999999860
MS>106 105 105.9999999999999900
MS>114 113 113.9999999999999900
MS>122 121 121.9999999999999900
MS>132 131 131.9999999999999700
MS>148 147 147.9999999999999700
MS>164 163 163.9999999999999700
MS>180 179 179.9999999999999700
MS>196 195 195.9999999999999700
MS>212 211 211.9999999999999700
MS>228 227 227.9999999999999700
MS>244 243 243.9999999999999700


MS>g++ v 2.95.3-5 еще хуже:

MS> 1 0 1.0000000000000000
MS> 2 1 2.0000000000000000
MS> 3 2 3.0000000000000000
MS> 4 3 4.0000000000000000
MS> 5 4 5.0000000000000000
MS> 6 5 6.0000000000000000
MS> 7 6 7.0000000000000000
MS> 8 7 8.0000000000000000
MS> 9 8 9.0000000000000000
MS> 10 9 10.0000000000000000
MS> 11 10 11.0000000000000000
MS> 12 11 12.0000000000000000
MS> 13 12 13.0000000000000000
MS> 14 13 14.0000000000000000
MS> 15 14 15.0000000000000000
MS> 16 15 16.0000000000000000
MS> 17 16 17.0000000000000000
MS> 18 17 18.0000000000000000
MS> 19 18 19.0000000000000000
MS> 20 19 20.0000000000000000
MS>. . .и т.д.

MS>Потестируйте пожалуйста на разных компиляторах.



VC7.1 полностью аналогично VC6.0
Re: Точность pow(x, 1.0)
От: _AK_ Россия  
Дата: 25.06.04 21:39
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Есть такой код:


MS>
MS>#include <math.h>
MS>#include <stdio.h>

MS>void main()
MS>{
MS>   int i;
MS>   for(i = 0; i < 256; i++)
MS>   {
MS>      int j = int(pow(double(i) / 255.0, 1.0) * 255.0);
MS>      double v = pow(double(i) / 255.0, 1.0) * 255.0;
MS>      if(j != i) printf("%3d %3d %20.16f\n", i, j, v);
MS>   }
MS>}
MS>


MS>В VC 6.0 при компиляции "cl a.cpp" работает нормально (ничего не печатает). С опцией /O2 выдает это:

MS> 33 32 32.9999999999999930
MS> 37 36 36.9999999999999930
MS> 41 40 40.9999999999999930
MS> 45 44 44.9999999999999930
MS> 49 48 48.9999999999999930
MS> 53 52 52.9999999999999930
MS> 57 56 56.9999999999999930
MS> 61 60 60.9999999999999930
MS> 66 65 65.9999999999999860
MS> 74 73 73.9999999999999860
MS> 82 81 81.9999999999999860
MS> 90 89 89.9999999999999860
MS> 98 97 97.9999999999999860
MS>106 105 105.9999999999999900
MS>114 113 113.9999999999999900
MS>122 121 121.9999999999999900
MS>132 131 131.9999999999999700
MS>148 147 147.9999999999999700
MS>164 163 163.9999999999999700
MS>180 179 179.9999999999999700
MS>196 195 195.9999999999999700
MS>212 211 211.9999999999999700
MS>228 227 227.9999999999999700
MS>244 243 243.9999999999999700


MS>g++ v 2.95.3-5 еще хуже:

MS> 1 0 1.0000000000000000
MS> 2 1 2.0000000000000000
MS> 3 2 3.0000000000000000
MS> 4 3 4.0000000000000000
MS> 5 4 5.0000000000000000
MS> 6 5 6.0000000000000000
MS> 7 6 7.0000000000000000
MS> 8 7 8.0000000000000000
MS> 9 8 9.0000000000000000
MS> 10 9 10.0000000000000000
MS> 11 10 11.0000000000000000
MS> 12 11 12.0000000000000000
MS> 13 12 13.0000000000000000
MS> 14 13 14.0000000000000000
MS> 15 14 15.0000000000000000
MS> 16 15 16.0000000000000000
MS> 17 16 17.0000000000000000
MS> 18 17 18.0000000000000000
MS> 19 18 19.0000000000000000
MS> 20 19 20.0000000000000000
MS>. . .и т.д.

MS>Потестируйте пожалуйста на разных компиляторах.



mingw 3.2 полностью аналогично gcc 2.95.3-5
Re: Точность pow(x, 1.0)
От: VladFein США  
Дата: 25.06.04 23:42
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Есть такой код:


MS>
MS>#include <math.h>
MS>#include <stdio.h>

MS>void main()
MS>{
MS>   int i;
MS>   for(i = 0; i < 256; i++)
MS>   {
MS>      int j = int(pow(double(i) / 255.0, 1.0) * 255.0);
MS>      double v = pow(double(i) / 255.0, 1.0) * 255.0;
MS>      if(j != i) printf("%3d %3d %20.16f\n", i, j, v);
MS>   }
MS>}
MS>


MS>В VC 6.0 при компиляции "cl a.cpp" работает нормально (ничего не печатает). С опцией /O2 выдает это:


А причем здесь точность?
32.9999999999999930, по-моему, очень близко к 33.
Ваш пример проверяет вероятность несущественной плавающей ошибки в меньшую сторону относительно такой же — в большую.
Re[2]: Точность pow(x, 1.0)
От: McSeem2 США http://www.antigrain.com
Дата: 26.06.04 01:50
Оценка:
Здравствуйте, VladFein, Вы писали:

VF>А причем здесь точность?

VF>32.9999999999999930, по-моему, очень близко к 33.
VF>Ваш пример проверяет вероятность несущественной плавающей ошибки в меньшую сторону относительно такой же — в большую.

Дык это понятно. Просто как-то оно неправильно, что при возведении числа в степень 1.0 оно портится. Портит именно pow(x, 1.0), а не умножение/деление на 255 — я проверял.
В общем, лечится добавлением 0.5 перед преобразованием к int.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re: Точность pow(x, 1.0)
От: Шахтер Интернет  
Дата: 26.06.04 02:04
Оценка:
Здравствуйте, McSeem2, Вы писали:

Надо не к int у приводить, что означает обрезание дробной части, а к ближайшему целому.

А что касается pow, то в наиболее общей реализации, он использует логарифмирование с последующим экспоненциированием.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[3]: Точность pow(x, 1.0)
От: Sir Wiz Россия  
Дата: 26.06.04 08:34
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, VladFein, Вы писали:


VF>>А причем здесь точность?

VF>>32.9999999999999930, по-моему, очень близко к 33.
VF>>Ваш пример проверяет вероятность несущественной плавающей ошибки в меньшую сторону относительно такой же — в большую.

MS>Дык это понятно. Просто как-то оно неправильно, что при возведении числа в степень 1.0 оно портится. Портит именно pow(x, 1.0), а не умножение/деление на 255 — я проверял.

MS>В общем, лечится добавлением 0.5 перед преобразованием к int.
Только для положительных чисел.

Например, для арифметического округления до первого десятичного знака я использовал такой код:

double wruRoundTenCent(double val)
{
    if (val >= 0.0)
        return floor((val * 10.0) + 0.5) / 10.0;
    else
        return -floor(((-val) * 10.0) + 0.5) / 10.0;
}


И ещё, хочу обратить внимание, когда пользуете printf, например с форматом %20.16f, помните, что он производит бухгалтерское(?), но не арифметическое округление.
... << RSDN@Home 1.1.3 stable >>
Re: Точность pow(x, 1.0)
От: barrett Россия  
Дата: 26.06.04 11:51
Оценка: 9 (1)
Здравствуйте, McSeem2, Вы писали:

MS>Есть такой код:

...
MS>Потестируйте пожалуйста на разных компиляторах.

Результаты могут зависеть от текущего режима округления сопроцесоора.
void main()
{

  unsigned short t;
  __asm fstcw word ptr t
  //t &= 0xF3FF; //near mode
  t |= 0x0C00; //truncate mode
  __asm fldcw word ptr t

   int i;
   for(i = 0; i < 256; i++)
   {
      int j = int(pow(double(i) / 255.0, 1.0) * 255.0);
      double v = pow(double(i) / 255.0, 1.0) * 255.0;
      if(j != i) printf("%3d %3d %20.16lf\n", i, j, v);
   }
}

Например, bcc 5.6 (с опцией -Od) выдает в режиме truncate:
1 0 0.9999999999999998
2 1 1.9999999999999997
3 2 2.9999999999999995
4 3 3.9999999999999995
5 4 4.9999999999999991
...
250 249 249.9999999999999715
251 250 250.9999999999999715
252 251 251.9999999999999715
253 252 252.9999999999999715
254 253 253.9999999999999715

В режиме near:
1 0 1.0000000000000000
2 1 2.0000000000000000
3 2 3.0000000000000000
4 3 4.0000000000000000
5 4 5.0000000000000000
и т.д...

С опцией -O2 результаты одинаковы
1 0 1.0000000000000000
2 1 2.0000000000000000
3 2 3.0000000000000000
4 3 4.0000000000000000
5 4 5.0000000000000000
и т.д....
Re[2]: Точность pow(x, 1.0)
От: McSeem2 США http://www.antigrain.com
Дата: 26.06.04 16:55
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Надо не к int у приводить, что означает обрезание дробной части, а к ближайшему целому.


А что стандарт предписывает по этому поводу? Или ничего не предписывает и надо явно использовать
floor()/ceil()?
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[3]: Точность pow(x, 1.0)
От: Шахтер Интернет  
Дата: 26.06.04 22:45
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, Шахтер, Вы писали:


Ш>>Надо не к int у приводить, что означает обрезание дробной части, а к ближайшему целому.


MS>А что стандарт предписывает по этому поводу?


Стандарт говорит, что пребразование плавающих чисел в целые осуществляется отбрасыванием дробной части.

123.456 -> 123
-123.456 -> -123

MS>Или ничего не предписывает и надо явно использовать

MS>floor()/ceil()?

floor и ceil возвращают нижнюю и верхнюю целые части в плавающем формате.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Точность pow(x, 1.0)
От: Tonal- Россия www.promsoft.ru
Дата: 27.06.04 09:08
Оценка:
MS>
MS>#include <math.h>
MS>#include <stdio.h>

MS>void main()
MS>{
MS>   int i;
MS>   for(i = 0; i < 256; i++)
MS>   {
MS>      int j = int(pow(double(i) / 255.0, 1.0) * 255.0);
MS>      double v = pow(double(i) / 255.0, 1.0) * 255.0;
MS>      if(j != i) printf("%3d %3d %20.16f\n", i, j, v);
MS>   }
MS>}
MS>


MS>Потестируйте пожалуйста на разных компиляторах.

Вывод icl 7.1 аналогичен VC-шному.
>icl /S /O3 /G6 pow.cpp

Но если посмотреть на asm, то ввычисления будут такие:
  mov       DWORD PTR [esp+32], esi                       ;7.28
  fild      DWORD PTR [esp+32]                            ;7.28
  fmul      QWORD PTR _2il0floatpacket$1                  ;7.28
  fmul      QWORD PTR _2il0floatpacket$3                  ;7.28
  fst       QWORD PTR [esp+24]                            ;7.28

Т.е. возведение в степень 1.0 вообще выкинуто.

Почему вычисление вообще не выкинуто — не совсем ясно, например для соответствия стандартам.
... << RSDN@Home 1.1.3 stable >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.