Программирование на Си (повышение точности)

Модератор: Модераторы разделов

Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Программирование на Си

Сообщение eddy »

drBatty писал(а):
23.09.2013 12:04
есть худший случай

Ты не забывай, что при сложении суммируются абсолютные погрешности, а при умножении - относительные. Поэтому сумма двух чисел с погрешностями по 3% будет иметь погрешность все те же 3%. А вот умножение двух чисел с погрешностями 3% будет иметь уже 6% погрешности!

А вот в случае с float - да, все числа представлены с точностью до FLT_EPSILON, поэтому если ты будешь складывать 100 раз одно и то же число само с собой, у тебя накопится 100FLT_EPSILON (ясен пень, абсолютная погрешность от этого не пострадает). Если же ты это число на 100 умножишь, то скорее всего абсолютная погрешность не изменится. И получится выгода: уменьшение относительной погрешности.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Программирование на Си

Сообщение drBatty »

eddy писал(а):
23.09.2013 12:39
Ты не забывай, что при сложении суммируются абсолютные погрешности, а при умножении - относительные. Поэтому сумма двух чисел с погрешностями по 3% будет иметь погрешность все те же 3%. А вот умножение двух чисел с погрешностями 3% будет иметь уже 6% погрешности!

это да. Потому-что при суммировании ты _точно_ знаешь, сколько раз ты складывал. А вот при умножении, тебе даже это неведомо. Потому-то HEX в данном случае удваивается. А при сложении HEX не изменяется.

К счастью, IRL многократное умножение на HEX практически никогда не имеет смысла. Умножение == переход к другой сущности, и число этих переходов ограничено (IRL значением 3.5, что безусловно символизирует)

Т.е. ты можешь перейти из длинны в площадь, и это удвоение HEX, можешь в объём и это утроение. Иногда можешь даже рассмотреть объём в изменении времени (а иногда не можешь. Потому-то 3.5*HEX). Дальше идти просто некуда, если ты не сатана. (:

Посему, умножение HEX в реальном мире строго ограничено числом 3.5, и только в фантазиях математиков оно может быть больше. (впрочем, математики вообще HEX ненавидят, у них даже значка для неё нет).
eddy писал(а):
23.09.2013 12:39
А вот в случае с float - да, все числа представлены с точностью до FLT_EPSILON, поэтому если ты будешь складывать 100 раз одно и то же число само с собой, у тебя накопится 100FLT_EPSILON (ясен пень, абсолютная погрешность от этого не пострадает). Если же ты это число на 100 умножишь, то скорее всего абсолютная погрешность не изменится. И получится выгода: уменьшение относительной погрешности.

у тебя по любому будет 100 FLT_ERSILON. А именно 100*2^-23.

НО: вот если ты своё x умножишь сначала на y, потом будешь складывать, а потом результат на этот y поделишь, тот получишь уже не 100eps, а y*100eps/x. И если y/x Over9000, то и ошибка возрастёт в Over9000 раз. ИЧСХ, если ты будешь даже складывать с y, а потом вычтешь 100*y, то проблема останется. Вот в случае численного интегрирования так и получается, что все эти маленькие параболы, которыми ты аппроксимируешь, СИЛЬНО приподняты над нулём.Именно по этой причине они обращаются сами в нуль. Посему, тупое применение метода Симпсона и даёт такой поганый результат.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Hephaestus
Сообщения: 3728
Статус: Многоуважаемый джинн...
ОС: Slackware64-14.1/14.2

Re: Программирование на Си

Сообщение Hephaestus »

Фантом писал(а):
22.09.2013 23:58
Не хочу портить столь интересную беседу, но при обсуждении вопросов такого рода все-таки стоит учитывать, что в природе существует целая наука под названием "вычислительная математика". Со своими проблемами, методами и т.д. И если ТС эта проблема волнует всерьез, то надо брать соответствующие книжки и внимательно их читать, разницей между Паскалем и Си это не определяется.
С этим я согласен.
Просто разница в результатах, полученных в Си и Паскале (FreePascal) ввела меня в заблуждение - я подумал, что в арсенале компилятора появилась некая новая фича, о которой я не знаю.
drBatty писал(а):
23.09.2013 00:07
это верно. Но в сишечке тоже есть своя специфика. И с этой т.з. тоже. ТС уже понял, что размер нигде не задан(точность и т.д.), но ещё не осознал, что это не баг, а фича.
Насчёт точности вышло интересно: Шилдт в справочнике пишет: "точность 6 знаков" , drBatty пишет: "точность не определена нигде". Если прав drBatty, опирающийся на стандарт, то непонятно на что опирается Шилдт.
drBatty писал(а):
23.09.2013 00:07
Даже программисты почему-то считают, что компьютеры ВСЁ и ВСЕГДА делают ТОЧНО.
Я так никогда не считал. О неточности машинного представления вещественных чисел я знал с самого начала. Просто меня FreePascal с толку сбил. В других компиляторах такого не было, а тут - пожалуйста - точность до 18 знака после запятой. Вот я и начал спрашивать, чего это такое. Оказалось, округление. Банально и неинтересно. Я ожидал чего-нибудь более оригинального.

В общем, тема себя исчерпала. Всем спасибо.
Пускай скрипят мои конечности.
Я - повелитель бесконечности...
Мой блог
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Программирование на Си

Сообщение drBatty »

fflatx писал(а):
23.09.2013 13:34
Просто разница в результатах, полученных в Си и Паскале (FreePascal) ввела меня в заблуждение - я подумал, что в арсенале компилятора появилась некая новая фича, о которой я не знаю.

спешу вас сразу поправить: ЯП тут не причём. Читайте man 3 printf (Linux Programmer's Manual)
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Программирование на Си

Сообщение drBatty »

fflatx писал(а):
23.09.2013 13:34
Насчёт точности вышло интересно: Шилдт в справочнике пишет: "точность 6 знаков" , drBatty пишет: "точность не определена нигде". Если прав drBatty, опирающийся на стандарт, то непонятно на что опирается Шилдт.

Шилдт опирается на свой компьютер. Раньше не было такого понятия "быдлокодер", а сейчас -- есть. Вот Шилдт по современным меркам -- быдлокодер.

И да, если-бы вы мне такой вопрос лет 15 назад задали, то я-бы вам как Шилдт ответил -- "где-то 6 знаков". Просто книжка очень старая.
fflatx писал(а):
23.09.2013 13:34
Я так никогда не считал. О неточности машинного представления вещественных чисел я знал с самого начала. Просто меня FreePascal с толку сбил. В других компиляторах такого не было, а тут - пожалуйста - точность до 18 знака после запятой. Вот я и начал спрашивать, чего это такое. Оказалось, округление. Банально и неинтересно. Я ожидал чего-нибудь более оригинального.

компьютеры разные бывают(и будут), потому достаточно глупо вводить какие-то искусственные ограничения в printf(3). Сейчас это 6 знаков, а завтра -- больше. И да. сейчас точность double == 1/4,503,599,627,370,496 что составляет где-то так 15..16 знаков. А float соответственно около 7..8.

ИМХО это уже не поменяют, компьютеры сейчас ворочают 256и битные числа, и если вы считаете float'ы, то они грызутся сразу по 8 штук. (32*8==256). Т.е. применять float'ы на практике == хорошая, годная идея, если их МНОГО.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Hephaestus
Сообщения: 3728
Статус: Многоуважаемый джинн...
ОС: Slackware64-14.1/14.2

Re: Программирование на Си

Сообщение Hephaestus »

drBatty писал(а):
23.09.2013 13:48
спешу вас сразу поправить: ЯП тут не причём.
Да я не про ЯП, я про компилятор. Досовский Borland Pascal, например, таких округлений не делал.
Нынешний FreePascal посовременней будет.
И я удивился, когда скомпилировал пример в FreePascal, а он мне такую точность выдал. Я подумал, чего-нибудь новенького появилось.
drBatty писал(а):
23.09.2013 14:00
Просто книжка очень старая.
Ну, тогда напоследок. Что можете посоветовать более новое? Я имею в виду вместо Шилдта.
И K&R у меня, выходит, тоже старая. Третье издание на русском языке, 2001 год. Но там стандарт C89, если не ошибаюсь. Компилятор в репах явно новее.
Посему, если можете дать рекомендации касательно литературы (справочники, учебники) буду признателен.
Пускай скрипят мои конечности.
Я - повелитель бесконечности...
Мой блог
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21261
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Программирование на Си

Сообщение Bizdelnick »

fflatx писал(а):
23.09.2013 15:05
Да я не про ЯП, я про компилятор. Досовский Borland Pascal, например, таких округлений не делал.
Нынешний FreePascal посовременней будет.
И я удивился, когда скомпилировал пример в FreePascal, а он мне такую точность выдал. Я подумал, чего-нибудь новенького появилось.

В fpc тип real - платформозависимый. Вы, поди, на x86_64 компилировали? Вот и получили удвоенную точность. Округления тут ни при чём. Если будете использовать тип single, расхождений быть не должно.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Программирование на Си

Сообщение drBatty »

fflatx писал(а):
23.09.2013 15:05
И я удивился, когда скомпилировал пример в FreePascal, а он мне такую точность выдал. Я подумал, чего-нибудь новенького появилось.

да вот, тут уже Bizdelnick подсказывает: в современных CPU "новенькое" появилось. И кстати, но старых CPU тип real мог-бы быть даже точнее, чем на новых, ибо вообще говоря, точность старых FPU (который сейчас никто не использует, ибо SSE лучше и быстрее), был 80и битный, что лучше 64х битного double.
fflatx писал(а):
23.09.2013 15:05
Ну, тогда напоследок. Что можете посоветовать более новое? Я имею в виду вместо Шилдта.
И K&R у меня, выходит, тоже старая.

K&R старая, но лучше её читать. Ибо от авторов. Они там вроде явно написали тоже самое, что и я говорю. Только намного более внятно.
Т.е. сначала K&R, а потом уже и всё остальное.
Ну как вторую книжку я посоветую Кнута "Искусство Программирования", дабы знать не только КАК писать, но и ЧТО писать.
fflatx писал(а):
23.09.2013 15:05
Но там стандарт C89, если не ошибаюсь. Компилятор в репах явно новее.

не забивайте голову. Стандарты практически полностью совместимы вверх, т.е ваш gcc практически полностью совместим с C89. Во всяком случае, простые примеры из K&R работать будут.
(вот как раз более новые книжки лучше НЕ брать, а то там Windows, а создатели маздая плевать хотели на все стандарты и вообще *%;№";№)
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5405
ОС: Gentoo

Re: Программирование на Си

Сообщение /dev/random »

fflatx писал(а):
23.09.2013 13:34
Насчёт точности вышло интересно: Шилдт в справочнике пишет: "точность 6 знаков" , drBatty пишет: "точность не определена нигде". Если прав drBatty, опирающийся на стандарт, то непонятно на что опирается Шилдт.


Стандарт C (по крайней мере, C99) не требует, но рекомендует компилятору поддерживать ISO/IEC 60559:1989. Если вы хотите, чтобы программа отказалась компилироваться без этой поддержки, включите в неё следующий код:

#ifndef _ _STDC_IEC_559_ _
#error "ISO/IEC 60559:1989 is required"
#endif
Спасибо сказали:
Аватара пользователя
Hephaestus
Сообщения: 3728
Статус: Многоуважаемый джинн...
ОС: Slackware64-14.1/14.2

Re: Программирование на Си

Сообщение Hephaestus »

Bizdelnick писал(а):
23.09.2013 15:22
Вы, поди, на x86_64 компилировали? Вот и получили удвоенную точность. Округления тут ни при чём.
Да, приведенные в первом посте результаты я получил на 64-битной системе.
Bizdelnick писал(а):
23.09.2013 15:22
Если будете использовать тип single, расхождений быть не должно.
Подверждаю, использование single даёт менее точные результаты.

Однако, всё не так просто.
Во-первых, если бы дело было только в разрядности, то gcc с аналогичным сишным кодом тоже дали бы такой результат при использовании long double, если уж результат влезает в 64 бита. Но этого не произошло. Значит, какое-то округление в FreePascal всё-таки есть.

Во-вторых, я попробовал в чруте 32-битный FreePascal и получил то же самое.
Не удовлетворившись этим, я развернул на виртуалке FreeDos и поставил туда FreePascal для DOS с таким же номером версии, как у меня в системе (2.6.0). Результат в FreeDos оказался таким же.
FreeDos вроде бы 32-битный, на всякий случай я скормил системе 4Гб памяти и убедился: видно только 3.5Гб, стало быть, действительно 32 бита.
Но это ещё не самое интересное.

Я по своей невнимательности не заметил (и никто из участников темы тоже не заметил), что результаты Borland Pascal и FreePascal различаются по количеству знаков.
Если Вы внимательно посмотрите первый пост, то увидите, что в коде указано вывести результат в формате 20:18, то есть 20 знаков, из них 18 после запятой. Borland Pascal именно так и вывел результат.
FreePascal же вывел после запятой только 15 знаков. Я заметил это только тогда, когда попытался вывести на экран ещё больше знаков (30:28).

FreePascal всё равно вывел только 15. Причина этого мне неизвестна и уже неинтересна.
Я потратил на это некоторое количество времени и не вижу смысла ковырять это дальше.
FreePascal действительно ввёл меня в заблуждение, это немного обидно и я больше с ним не дружу.
Однако в большей степени всё из-за моей невнимательности.

Я прошу всех участников темы извинить меня за то, что я занял ваше время.
Я благодарю всех вас за участие и за ваши советы, которые для меня действительно ценны.
Пускай скрипят мои конечности.
Я - повелитель бесконечности...
Мой блог
Спасибо сказали:
Аватара пользователя
bormant
Сообщения: 1354

Re: Программирование на Си

Сообщение bormant »

fflatx
ничего нового, вы просто не пользовались возможностями tp/bp.
При {$N+} доступны сопроцессорные типы single, double, extended, currency. Real в tp/bp программный 48-битный. В fpc такого (48-битного) типа нет, вместо него используется double ( http://www.freepascal.org/docs-html/ref/refsu6.html ), для вычислений -- extended, отсюда и меньшая погрешность.
В число целевых процессоров tp/bp входил 8086, математический сопроцессор 8087 к нему был отдельным чипом и мог отсутствовать, поэтому поведение компилятора для {$N+} дополнительно управлялось директивой {$E} -- использовать библиотеки эмуляции 8087 или железку.
Turbo Pascal 5.5, "музейная" версия:

Код: Выделить всё

{$N+,E-}
a, b: extended;
a=0.200000000000000000; b=10.000000000000000000

a, b: double;
a=0.200000000000000011; b=9.999999999999996450

a, b: single;
a=0.200000002980232239; b=9.999995231628417970

a, b: real;
a=0.200000000000045475; b=9.999999999927240420

Для {$N+,E+} значения те же.
Спасибо сказали:
Аватара пользователя
Hephaestus
Сообщения: 3728
Статус: Многоуважаемый джинн...
ОС: Slackware64-14.1/14.2

Re: Программирование на Си

Сообщение Hephaestus »

bormant писал(а):
25.09.2013 08:35
ничего нового, вы просто не пользовались возможностями tp/bp.
При {$N+} доступны сопроцессорные типы single, double, extended, currency. Real в tp/bp программный 48-битный. В fpc такого (48-битного) типа нет, вместо него используется double ( http://www.freepascal.org/docs-html/ref/refsu6.html ), для вычислений -- extended, отсюда и меньшая погрешность.
Касаемо FreePascal. Я правильно понял, что даже если объявить переменную как real, вычисления будут производиться в extended? Если так, это как раз новое, по сравнению с Borland Pascal: объявить real и неявно получить точность в extended. В BP такого не было. Но как-то это очень неочевидно. Это где-нибудь декларируется? По Вашей ссылке об этом не сказано.
И опять же неясно, почему на 64-битной машине сишный тип long double, который имеет такой же размер как паскалевский extended (оба 80 бит) не даёт аналогичной точности. Если уж результат влезает в 80 бит практически без погрешности, то, согласитесь, для типов одного размера должно получиться одинаково.
Всё-таки free pascal делает что-то неявно, мудрит, одним словом.

Пускай скрипят мои конечности.
Я - повелитель бесконечности...
Мой блог
Спасибо сказали:
Аватара пользователя
Hephaestus
Сообщения: 3728
Статус: Многоуважаемый джинн...
ОС: Slackware64-14.1/14.2

Re: Программирование на Си

Сообщение Hephaestus »

fflatx писал(а):
25.09.2013 12:33
И опять же неясно, почему на 64-битной машине сишный тип long double, который имеет такой же размер как паскалевский extended (оба 80 бит) не даёт аналогичной точности. Если уж результат влезает в 80 бит практически без погрешности, то, согласитесь, для типов одного размера должно получиться одинаково.
Нагло вру. Если в Си использовать long double и выводить результат с точностью 15 знаков, то да, получается так же, как в Free Pascal. Теперь всё встало на свои места.
Пускай скрипят мои конечности.
Я - повелитель бесконечности...
Мой блог
Спасибо сказали:
Аватара пользователя
bormant
Сообщения: 1354

Re: Программирование на Си

Сообщение bormant »

fflatx писал(а):
25.09.2013 12:33
Касаемо FreePascal. Я правильно понял, что даже если объявить переменную как real, вычисления будут производиться в extended?
Это я неточно выразился. Для вычисления действительных констант на этапе компиляции используется extended, значение результата приводится к типу переменной:

Код: Выделить всё

var
  a: Real;
begin
  a :=
    0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+
    0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+
    0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+
    0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+
    0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2+0.2;
  WriteLn(a);
end.
50 по 0.2 равно 10.0:

Код: Выделить всё

...
# [4] a :=
    movq    _$PROGRAM$_Ld1,%rax
    movq    %rax,U_P$PROGRAM_A
...
.globl    _$PROGRAM$_Ld1
_$PROGRAM$_Ld1:
# value: 0d+1.00000000000000E+001
    .byte    0,0,0,0,0,0,36,64
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Программирование на Си

Сообщение drBatty »

fflatx писал(а):
25.09.2013 03:59
Если Вы внимательно посмотрите первый пост, то увидите, что в коде указано вывести результат в формате 20:18, то есть 20 знаков, из них 18 после запятой.

дык там же мусор после 15го знака. Какая разница?

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

man bc

bc(1) General Commands Manual bc(1) NAME bc - An arbitrary precision calculator language SYNTAX bc [ -hlwsqv ] [long-options] [ file ... ] DESCRIPTION bc is a language that supports arbitrary precision numbers with inter- active execution of statements. There are some similarities in the syntax to the C programming language. A standard math library is available by command line option. If requested, the math library is defined before processing any files. bc starts by processing code from all the files listed on the command line in the order listed. After all files have been processed, bc reads from the standard input. All code is executed as it is read. (If a file contains a command to halt the processor, bc will never read from the standard input.)

http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Hephaestus
Сообщения: 3728
Статус: Многоуважаемый джинн...
ОС: Slackware64-14.1/14.2

Re: Программирование на Си

Сообщение Hephaestus »

drBatty писал(а):
25.09.2013 21:04
дык там же мусор после 15го знака. Какая разница?
Вы уже отвлеклись от темы? Разница такая, что gcc выдаёт мусор, Borland Pascal выдаёт мусор, а FreePascal не выдал мусора. Стало интересно, почему не выдал и как сделать, чтобы gcc тоже не выдавал - так возникла данная тема. Потом, когда я заметил, что FreePascal выводит 15 знаков, хотя было велено 18, да ещё использует extended, стало ясно, почему он не выдал мусор. И gcc, как выяснилось, при long double и 15 знаках тоже мусор не выдаёт. Таким образом, всё встало на свои места.
Пускай скрипят мои конечности.
Я - повелитель бесконечности...
Мой блог
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Программирование на Си

Сообщение drBatty »

fflatx писал(а):
25.09.2013 22:27
И gcc, как выяснилось, при long double и 15 знаках тоже мусор не выдаёт.

ну вам просто повезло. Так совпало.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали: