Программистское

Dec 14, 2013 23:17

Далее под катом немного кода на СИ и одна проблема. Если у вас есть немного свободного времени и вы программист, то я буду очень рад помощи.
Помочь... )

Leave a comment

_winnie December 27 2013, 08:45:06 UTC
Да, в целях сохранения душевного здоровья - лучше считать что в разных "системах" - разные синусы. Под "системами" я понимаю связку не просто процессор, а связку процессор+математическая библиотека+компилятор.

Это можно победить, но лучше считать что они разные.

Ну да, динамические ситесмы они такие, но как бы и не страшно - погрешность измерительных приборов гораздо больше, чем погрешность double. Есть ещё более страшная проблема - погрешность модели. Если вы эмулируете физический процесс, то вы не учли ветер, изменение гравитации от высоты, или ещё что-нибудь.

Reply

goliafffff December 27 2013, 16:44:45 UTC
У меня тут больше математическая задача. Если в аргументе синуса стоит M_PI/30.0*ds.t, то я получаю различные результаты. Если же заменить M_PI/30.0 на приблизительное 0.10471975511966, то всё встаёт на свои места. На сколько я понимаю корень зла кроется в ошибки округления при делении на 30.0.

Как это можно победить?

Reply

_winnie December 27 2013, 17:37:45 UTC
В общем случае множество действительных чисел в один double не засунешь.
Нужно вдумываться в конкретную задачу.

Вычислениями на компьютере можно проверить, что два выражения очень близки, но невозможно доказать что два выражения в точности равны.

Например, с точки зрения double ( cos(0.00000001) - 1 ) в точности равно нулю, но это не значит что 0.00000001 -- неподвижная точка для (cos(x)-1+x)

Reply

birdwatcher December 27 2013, 17:47:06 UTC
Я согласен с аргументом про общий случай, но данный случай очень частный. Если я правильно понял автора, он сводится к разному поведению деления на двух разных ieee-совместимых машинах. Я бы безусловно ожидал побитового совпадения. А сейчас бы, соответственно, распечатывал двоичное представление М_PI / 30.0 в обоих случаях.

Reply

birdwatcher December 27 2013, 18:13:57 UTC
P.S. а до этого посмотрел бы на результат работы препроцессора, во что это M_PI превращается в коде.

Reply

_winnie December 27 2013, 18:41:18 UTC
В сгенерированный машинный код надо смотреть ещё, M_PI/30 может вычисляться на этапе компиляции, в зависимости от флажков оптимизации компилятора

Reply

birdwatcher December 27 2013, 18:46:25 UTC
Надеюсь, что вычисляется на этапе компиляции! Кстати, будет смешно, если окажется, что деление в собственном коде работает правильно, а в кодогенераторе сломано.

Reply

goliafffff December 28 2013, 14:22:17 UTC
Логика рассуждений мне понятна, но, честно говоря, я не знаю как посмотреть сгенерированный машинный код или результат работы препроцессора. Вообще очень странно, что на разных компьютерах разный результат. Просто если дело в округлении результата деления M_PI на 30, то в рамках моей задачи это будет означать немного другую частоту в системе, и статистические характеристики, которые я считаю могут, измениться (и то не сильно) количественно, но должны подчиняться теоретической закономерности. Не понятно почему при задании частоты через M_PI/30.0 появляется систематическая погрешность.

Reply

birdwatcher December 28 2013, 14:33:26 UTC
Пост-препроцессорный код увидеть очень легко, см. например
http://stackoverflow.com/questions/5034209/how-do-i-see-what-a-file-looks-like-after-preprocessing

Это будет обычный C, в котором развернуты все #include, #define, #if и проч. Вместо M_PI будет стоять число в десятичной записи, надо убедиться, что оно одинаковое на двух машинах.

На последний вопрос, ничего не зная про задачу, ничего путного не отвечу.

Reply

_winnie December 27 2013, 18:14:35 UTC
На всякий случай:

1) Есть библиотеки и программы для расчетов с произвольной точностью. "произвольная" не значит "бесконечная". Т.е. вам допустим нужен результат с точностью до 22 знаков после запятой. Вы опытным путём или на бужаке понимаете, что для этого достаточно 1000 знаков (или 10000) после запятой, ну и считаете с такой точностью.

2) Есть библиотеки для символьных вычислений, которые преобразуют формулы, а не числа.

Подходит это или нет - зависит от задачи. Может реорганизацией вычислений хватит и double, а может у вас хаотическая система, которой и "произвольной" точности не хватит (ну невозможно иррациональное число приблизить какой-то точностью), или мощности символьных вычислений не хватит (например, попробуйте доказать что последовательность n = (n mod 2 == 0) ? n/2 : 3n*1 сходится к 1 для всех целых n).

Reply

goliafffff December 28 2013, 14:25:32 UTC
Можете дать ссылки на информацию о библиотеках с произвольной точностью?

Reply

_winnie December 29 2013, 10:38:01 UTC
Я сам ими не пользовался, так что буду вбивать в гугл arbitrary precision ( https://www.google.com/search?q=arbitrary+precision ) искать столько же времени, сколько и вы

Я бы почитал такое -
1) http://stackoverflow.com/questions/4486882/whats-the-best-for-speed-arbitrary-precision-library-for-c

И возможно, использовал бы не C, а привычную нотацию в
2) калькуляторе bc
3)
python и
а) его модуль decimal (только sin/cos нужно будет считать самому)
б) библиотека sympy (помимо расчетов произвольной точности, она умеет символьные вычисления, типа sympy.summation(1/(n*n), (n, 1, oo)) равно pi**2/6 )
в) библиотека mpmath

Могу переписать ваш сишный код на python по доллару за строчку :)

Reply

pphantom December 29 2013, 10:59:42 UTC
Для C есть практически стандартная библиотека MPFR.

Reply


Leave a comment

Up