Страниц: [1]
  Печать  
Автор Тема: Жестокая ошибка в <complex> в dincum c++ или нуль в квадрате - уже не число  (Прочитано 7890 раз)
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« : Мая 13, 2010, 09:18:42 am »

Транслирую программу под QNX 6.4.1. Программа, мэйкфайл, и результат выполнения приведены ниже.

Test.cpp
Код:
#include <stdio.h>
#include <complex>

int main() {
  std::complex<double> R;
  
  R = pow( std::complex<double>(0.,0.), 2. );
  printf("( %f ; %f )\n", real(R), imag(R) );
  
  R = pow( std::complex<double>(0.,0.), 2 );
  printf("( %f ; %f )\n", real(R), imag(R) );
}

Makefile
Код:
CC  = QCC
CXX = QCC
LD  = QCC

all: Test

OBJS = Test.o
LIBS = -lm
CPPFLAGS = -Vgcc_ntox86 -Y_cpp -lang-c++ -w8 -O

Test: $(OBJS)
QCC -Vgcc_ntox86 -lang-c++ -oTest $(OBJS) $(LIBS)

clean:
rm -f *.o Test

Результат
Код:
( -nan ; -nan )
( 0.000000 ; 0.000000 )

То есть комплексное число 0 возводится правильно в целую степень и неправильно, если показатель степени имеет тип double.
В 6.3.2 все работало правильно.
Если в мэйкфайле исправить -Y_cpp на -Y_gpp -использовать не Dincum C++, а GNU: с double все работает правильно,
правда на возведение в целую степень компилятор ругается.
« Последнее редактирование: Мая 13, 2010, 09:20:52 am от gleb » Записан
qnxloder
Sr. Member
****
Offline Offline

Сообщений: 292


Просмотр профиля
« Ответ #1 : Мая 13, 2010, 04:10:36 pm »

Вот, что нашел в хэлпе 6.4.0:
(Ref# 58590, 59482)
Dinkum libraries
   We've upgraded to Dinkumware version 5.0. For information about the
   changes to the libraries, see
   http://www.dinkumware.com/WhatsChanged.aspx. The new libraries include
   at least the following corrections:
     o   If you call pow( x, 2.0f ), the function no longer returns infinity for
      small values of x.
Попробуйте R = pow( std::complex<double>(0.,0.), 2. 0f);
Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #2 : Мая 14, 2010, 06:30:23 am »

Не возводится в степень только ноль, с очень маленькими числами все работает правильно.
pow( x, 2.0f ) - это, похоже, операция с действительными числами. Для комплексных, если верить хелпу, есть 4 шаблона:
Код:
template<class Ty>
    complex<Ty> pow(const complex<Ty>& left, int right);
template<class Ty>
    complex<Ty> pow(const complex<Ty>& left, const Ty& right);
template<class Ty>
    complex<Ty> pow(const complex<Ty>& left,
        const complex<Ty>& right);
template<class Ty>
    complex<Ty> pow(const Ty& left, const complex<Ty>& right);
Из них число 0 правильно возводят в степень первая и последняя.
Другие две выдают ( -nan; -nan ).
Попытка задать показатель типа float при аргументе complex<double> приводит к ошибке компиляции, потому что такого шаблона нету.
В принципе, все исправляется добавлением одного уcловия
Код:
std::complex<double> MyPow( std::complex<double> const &X, double Y ) {
  return (X==0.)? 0 : pow( X, Y );
}
Так все работает. Однако наблюдаются еще кое-какие странные вещи, про которые напишу позже, когда разберусь до конца.
Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #3 : Мая 14, 2010, 09:13:15 am »

Отправил bug report на support@dinkumware.com. Вот ответ:

The bug is in the header <xcomplex>. You need to change:
Код:
// TEMPLATE FUNCTION pow
_TMPLT(_Ty) inline
_CMPLX(_Ty) pow(const _CMPLX(_Ty)& _Left, const _Ty& _Right)
{ // return complex ^ real
if (imag(_Left) == 0 && 0 < real(_Left))
return (_CMPLX(_Ty)(_CTR(_Ty)::pow(real(_Left), _Right)));
else
return (exp(_Right * log(_Left)));
}
to:
Код:
// TEMPLATE FUNCTION pow
_TMPLT(_Ty) inline
_CMPLX(_Ty) pow(const _CMPLX(_Ty)& _Left, const _Ty& _Right)
{ // return complex ^ real
if (imag(_Left) == 0)
return (_CMPLX(_Ty)(_CTR(_Ty)::pow(real(_Left), _Right)));
else
return (exp(_Right * log(_Left)));
}
Thanks for pointing out the problem.
Best regards,
P.J. Plauger

После внесения изменений все работает правильно
Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #4 : Мая 14, 2010, 10:03:23 am »

Перекомпилировал проект, который работал в QNX 6.3.2, под 6.4.1. Это программа, которая выполняет математические расчеты. Запускаю для проверки: все отлично, получаю точно такой же результат, что и в 6.3.2 (до 12-го знака, точнее не сравнивал, потому что в этой задаче не надо). Но все-таки что-то не так: в 6.3.2 расчет длится 6 секунд, в 6.4.1 - 55 секунд. Видимо, что-то случилось Smiley
А виновата опять-таки эта функция pow()!
Обнаружилась интересная вещь: если мнимая часть числа, возводимого в степень, не равна 0, быстродействие функции нормальное. А вот если возводится число с нулевой мнимой частью: время выполнения возрастает на 1-2 порядка. Об этом пишу в другой теме, потому что, как оказалось, комплексные числа тут уже не причем (http://qnx.org.ru/forum/index.php?topic=6435.msg52982#msg52982)
Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #5 : Мая 18, 2010, 10:29:18 am »

Это уже слишком...
Код:
pow( std::complex<double>(-1.,0.) , 1./3. );
возвращает (nan,0).
В 6.3.2 возвращало (0.5,0866025)

P.S.  Все, надоело, пишу свою функцию возведения в степень и везде заменяю pow на нее
P.P.S.  Один дурак может наделать больше багов, чем десять умных найти
P.P.P.S  lestat: Now I don't trust anything too
« Последнее редактирование: Мая 18, 2010, 11:05:18 am от gleb » Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #6 : Мая 18, 2010, 11:23:24 am »

Разобрался: последний баг появился в результате исправления по совету support@dinkumware.com Smiley
Интересно, они там вообще как-нибудь тестят результаты своего творчества или нет?
Исправил у себя в файле /usr/qnx641/target/qnx6/usr/include/cpp/c/xcomplex функцию pow():
Код:
// TEMPLATE FUNCTION pow
_TMPLT(_Ty) inline
_CMPLX(_Ty) pow(const _CMPLX(_Ty)& _Left, const _Ty& _Right)
{ // return complex ^ real
if (imag(_Left) == 0 && 0 <= real(_Left))
return (_CMPLX(_Ty)(_CTR(_Ty)::pow(real(_Left), _Right)));
else
return (exp(_Right * log(_Left)));
}
Стало вычисляться правильно. Причина глюка: функция pow(double, double) с отрицательными числами при дробных показателях степени не работает.
Записан
gosh@
Участник
*
Offline Offline

Сообщений: 1


Просмотр профиля
« Ответ #7 : Мая 20, 2010, 11:19:03 am »

Нас в университете учили, что возводить в степень лучше умножением требуемое количество раз, потому что умножение выполняется аппаратно, следовательно гораздо быстрее.
Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #8 : Мая 21, 2010, 11:23:11 am »

gosh@:
Интересно, как это вас в университете научили аппаратно умножать число само на себя 0.333 раза?  Grin
Записан
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #9 : Мая 21, 2010, 06:16:33 pm »

Неправильные университеты делают неправильный мед.  Grin
Записан
lastcross
Full Member
***
Offline Offline

Сообщений: 224


Просмотр профиля
« Ответ #10 : Мая 21, 2010, 06:42:53 pm »

Цитировать
Причина глюка: функция pow(double, double) с отрицательными числами при дробных показателях степени не работает.

Тут к примеру что-то про ограничения параметров сказано.
http://www.cplusplus.com/reference/clibrary/cmath/pow/

Я бы даже сказал так - сам pow (не перегруженный под комплесный тип) имеет правильные ограничения. По сути возведением отрицательного числа в дробную степень (вспомним точность представления машиной чисел с плавающим знаком) вполне можем получить кратную двойке степень. К примеру (-1) в степени (1/12) - резве имеет решение? А как данная степень ляжет в float или double ? Кратность двойки не очевидна.

Если у вас есть "очевидные" решения для вашего случая (в частности для комплексного типа) -вероятно можно перегрузить метод или в крайнем случае составить свой комплексный тип на базе библиотечного.



« Последнее редактирование: Мая 21, 2010, 06:47:00 pm от lastcross » Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #11 : Мая 22, 2010, 07:39:04 am »

Я ничего против pow(double,double) не имею, в документации под QNX про нее сказано то же самое - отрицательные числа в дробную степень не возводит. А вот в xcomplex в SDP 6.4.1 действительно ошибка, раньше под 6.3.0 ... 6.3.2 все работало правильно. Если исправить, как я написал последний раз, то и в 6.4.1 будет работать правильно. Я протестил с разными числами.
Записан
Страниц: [1]
  Печать  
 
Перейти в: