forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   FAQ (http://forum.boolean.name/forumdisplay.php?f=15)
-   -   Математика в Blitz3D (http://forum.boolean.name/showthread.php?t=2451)

impersonalis 19.01.2007 21:39

Математика в Blitz3D
 
Сколько твердили миру, что Blitz3D - не для математических расчётов, но - нет: я опять взялся писать странющую прогу, прельщённый лёгкой поддержкой графических форматов и простотой синтаксиса. То что уже было мною набрано на С++ я портировал на b3d и тут понеслось.
Пример раз:
Код:

Graphics 800,600
SetBuffer BackBuffer()
SetFont LoadFont("MS Sans Serif",20)

Local intervalx#[20]
Local temp0#,temp1#,temp2#,tempc%,b#
x#=14.143

xmax#=15.051

h#=0.242
temp0=13.417
tempc=1
While (temp0<=xmax)
        temp2=temp0+h       
        intervalx[tempc]=temp2
        temp0=temp2
        tempc=tempc+1
Wend

b=intervalx[3]


If  x=b
        Print ""+x+"="+b
Else
        Print ""+x+"<>"+b
EndIf



WaitKey()
End

Не знаю как у вас, а у меня в 1.98/1.98/1.98 скомпиленный ехе пишет, что 14.143<>14.143. И это, как видно из кода, не тривиалное переполнение буфера отладчика. Лечится например так:
Делаем "волшебную" конвертацию типов число->строка->число
Код:

b=Float(Str(b))
Теперь обрабатываем сравниваемое число в коде выше:
Код:



Graphics 800,600
SetBuffer BackBuffer()
SetFont LoadFont("MS Sans Serif",20)

Local intervalx#[20]
Local temp0#,temp1#,temp2#,tempc%,b#
x#=14.143

xmax#=15.051

h#=0.242
temp0=13.417
tempc=1
While (temp0<=xmax)
        temp2=temp0+h       
        intervalx[tempc]=temp2
        temp0=temp2
        tempc=tempc+1
Wend

b=intervalx[3]
b=Float(Str(b))


If  x=b
        Print ""+x+"="+b
Else
        Print ""+x+"<>"+b
EndIf



WaitKey()
End

Теперь программа пишет, что "14.143=14.143".
Потрясающе! Мой 80кб-ый алгоритм прекрасно работал и обработал несколько сотен значений, пока я не получил на выходе коэффициент корреляции, превосходящий единицу! Программа сгенерировала 16-листов формата А4 вычислений. И всё это пришлось проверять вручную, затем ковыряться в логе отладчика (я впервые пожалел, что в нём нет поиска) - и всё это из-за одного числа.
Пример два:
Оператор INT в Blitz3D, в отличие от C++ не отбрасывает дробную часть, а округляет число. о_0 Для меня было неожиданностью.
Пример три:
Переполнение буфера отладчика поможет вам сойти с ума в процессе отладки рабочего алгоритма:
http://www.boolean.name/showthread.php?t=550
Пример 4етыре:
В ходе написания всё той же проги я столкнулся и с тем что сумма целых чисел волшебным образом преобразуется из например 6 в 5.999, если переменные, используемый в вычисленяих были float-типа.

--------------------
Я НЕ СУМАСШЕДШИЙ!

ZanoZa 20.01.2007 11:08

Re: Математика в Blitz3D
 
о последнем кажется ещё Jimon упомиинал :)

jimon 20.01.2007 13:17

Re: Математика в Blitz3D
 
ага было такое
когда делиш на 0 и ошибки не выскакивает
0 магическим способом превращается в 0.00001 :)

impersonalis 20.01.2007 16:24

Re: Математика в Blitz3D
 
Цитата:

Сообщение от ZanoZa
о последнем кажется ещё Jimon упомиинал :)

Ели бы я не поинтерсовался, он бы не так быстро это заметил ;)
Так - а первый пример у всех работает неправильно?

impersonalis 23.01.2007 02:44

Re: Математика в Blitz3D
 
Тест на С++ показал, что проблема в типе переменной. Корректно начинает работать с 8-байтовыми (double)
Код:

#include<iostream.h>
#include<conio.h>

template<class abstr>
void calc(abstr formal)
{       
        cout<<"===\n";
        cout<<"for "<<sizeof(formal)<<" bytes"<<endl;
        abstr intervalx[20];
        abstr temp0,temp1,temp2,b;
        short tempc;
        abstr x=14.143;
        abstr xmax=15.051;
        abstr h=0.242;
        temp0=13.417;
        tempc=1;
        while(temp0<=xmax){
                temp2=temp0+h;
                intervalx[tempc]=temp2;
                temp0=temp2;
                tempc++;
        }

        b=intervalx[3];

        if(x==b)
                cout<<x<<"="<<b<<endl;
        else
                cout<<x<<"!="<<b<<endl;
        cout<<"===\n";
       
}

void main()
{
        float x1;
        double x2;
        calc(x1);
        calc(x2);
        cout<<endl;
        getch();
}

Цитата:

===
for 4 bytes
14.143!=14.143
===
===
for 8 bytes
14.143=14.143
===

jimon 23.01.2007 08:56

Re: Математика в Blitz3D
 
странно... надо на разных компах посмотреть
обычно double имеет привычку "плыть"
....
сорс пришлось поправить :) а то там с stl трабла :) компиляторы разные
но результат с тобой одинаковый
* тут че то не то :)

alcoSHoLiK 23.01.2007 13:15

Re: Математика в Blitz3D
 
Достаточно такую штуку написать:
Код:

        float t1;
        double t2;

        t1=14.143;
        t2=14.143;

        if (t1==t2)
                cout<<t1<<"="<<t2<<endl;
        else
                cout<<t1<<"!="<<t2<<endl;

Результат будет "!=". Помогло только такое сравнение
Код:

if (t1==float(t2))
Это должно быть связано с отличием представления данных в формате float и double. От нас что-то скрывают.

Но встает вопрос, почему то же самое творится в блице, если там только float.
Код:

x=14.143
b=14.142
b=b+.001

If  x=b
        Print ""+x+"="+b
Else
        Print ""+x+"<>"+b
EndIf

Выдает "<>". Тут, похоже, действует прикол блица представлять числа в виде 14.14300001 или 14.14299999 или что-то типа того, а при выводе нам это не показывают.

ABTOMAT 28.12.2008 02:53

Ответ: Математика в Blitz3D
 
Видимо, это какой-то масонский заговор во главе с Марском Сибли... :wild:

IGR 30.12.2008 16:22

Ответ: Математика в Blitz3D
 
хех...
Код:

x#=14.143
b#=14.142
b#=b+0.001
If  x=b
Print ""+x+"="+b
Else
Print ""+x+"<>"+b
EndIf
WaitMouse()

так неравно
Код:

x#=14.143
b#=14.142
b#=b+0.001
x = Float(Str(x))
b = Float(Str(b))
If  x=b
Print ""+x+"="+b
Else
Print ""+x+"<>"+b
EndIf
WaitMouse()

а так равно !!

SBJoker 30.12.2008 17:02

Ответ: Математика в Blitz3D
 
Программисты, сколько можно, ну всюду же везде в любой книге пишут что нельзя применять оператор сравнения = для переменных с плавающей точкой. Т.к. переменные с плавающей точкой имеют ограничение по точности, и 2е переменные типа float будут равны только в случае если они обе были установлены идентичными выражениями или установлены одна от другой.

Повторим ещё раз "Оператора = для переменных с плавающей запятой несуществует"

impersonalis 30.12.2008 20:22

Ответ: Математика в Blitz3D
 
2SBJoker вы сударь последнее время критикуете всё с такой яростью, что вам в пору иметь более брутальный никнейм, это во-первых. Во-вторых, что за традиция ссобщать всё пост-фактум? До последнего молчать обо всех алгоритмических изысках,а потом "бойааанЪ". В-третьих, я не встречал высказнного вами "очевидного" правила ни в одной (!) прочитанной книге. В-четвёртых это нихрена не очевидно, что функция вывода возрващает число Х, которое на саммом деле нифига не Х (при том, что функция никак не модифицирует число) и, в-пятых, совсем колдунство - пропускание флоат-а через String type cast. В-шестых:
Цитата:

переменные с плавающей точкой имеют ограничение по точности, и 2е переменые типа флоат будут равны только в случае если они обе были установлены идентичными выражениями или установлены одна от другой.
Вы понимаете - в примере не использованы связки деление-умножение (приводящие к потери точности из-за апроксимации бесконечнй дроби конечной мантиссой), вовлечённые в операции константы и результаты операций далеки от переполнения формата - т.е. ещё раз "нихрена не очевидно".
В-седьмых: концепт "Злобный Модератор" вырождается в концепт "Злобный дед", такие люди читают орфографическое правило с примером неверного написания слова, и забыв про контекст, черкают ручкой ошибочное место. Попутно послыая и автора и отсальных читателей.

2IGR и? ты повторил кусок моей заметки с моим выводом - и что?

SBJoker 30.12.2008 21:52

Ответ: Математика в Blitz3D
 
Цитата:

Сообщение от impersonalis (Сообщение 93205)
2SBJoker вы сударь последнее время критикуете всё с такой яростью, что вам в пору иметь более брутальный никнейм, это во-первых.

Вы меня ни с кем не путаете? Я вообще крайне редко пишу в форум без веских причин.
Цитата:

Сообщение от impersonalis (Сообщение 93205)
Во-вторых, что за традиция ссобщать всё пост-фактум? До последнего молчать обо всех алгоритмических изысках,а потом "бойааанЪ".

В мои обязаности не входит учить форумчан основам программирования, считается что базовые правила знают все.

Цитата:

Сообщение от impersonalis (Сообщение 93205)
В-третьих, я не встречал высказнного вами "очевидного" правила ни в одной (!) прочитанной книге.

М.б. вы читали не те книги или не так подробно. Или просто пропустили раздел "для самых маленьких" как тот в котором Вам давно всё извесно.

Вот пример:
"Избегайте сравнений на равенство. Числа с плавающей запятой, которые должны быть равны, на самомо деле равны невсегда. Главная проблема в том, что два разных способа получить одно и тоже число не всегда приводит к одинаковому результату."

"Совершенный код", С.Макконелл, издательства Microsoft, Питер, Русская редакция/ стр.286, последний абзац.

Всем очень рекомендую почитать эту книгу, даже самые самоувереные гуру-программисты найдут много полезного и то чего они сами незнали.

Цитата:

Сообщение от impersonalis (Сообщение 93205)
В-четвёртых это нихрена не очевидно, что функция вывода возрващает число Х, которое на саммом деле нифига не Х (при том, что функция никак не модифицирует число) и, в-пятых, совсем колдунство - пропускание флоат-а через String type cast. В-шестых:

Вы понимаете - в примере не использованы связки деление-умножение (приводящие к потери точности из-за апроксимации бесконечнй дроби конечной мантиссой), вовлечённые в операции константы и результаты операций далеки от переполнения формата - т.е. ещё раз "нихрена не очевидно".

Любая, я подчёркиваю любая операция с вещественными цислами запускает махенизм перекомпоновки числа в отведёную ему память. Это неизбежно приводит к округлению последнего знака.

Цитата:

Сообщение от impersonalis (Сообщение 93205)
В-седьмых: концепт "Злобный Модератор" вырождается в концепт "Злобный дед", такие люди читают орфографическое правило с примером неверного написания слова, и забыв про контекст, черкают ручкой ошибочное место. Попутно послыая и автора и отсальных читателей.

Спасибо за оценку.

SBJoker 13.01.2009 12:00

Ответ: Математика в Blitz3D
 
Вот специально решил выложить инфу из MSDN по типам переменных, это актуально и для встроенных типов Blitz3D:
Цитата:

float:
Примерные приделы значений: от ±1.5 * 10^-45 до ±3.4 * 10^38 (крайние приделы по сути не имеют дробной или целой части.)
Точность: 7 цифр (т.е. в числе без потери точности может быть не более 7 цифр в сумме из целой и дробной частей.)
Что из этого следует? В любом языке 32х битный float ограничен 7 цифрами в числе. Т.е. если мы хотим работать с точностью до 3его знака в дробной части, то целая часть недолжна превышать 4 знаков или числа 9999 (на самом деле число может быть чуть больше из-за несоответствий между десятичной и двоичной системами счисления). Если мы хотим работать с числами в целой части которых 7 знаков, то можно забыть о дробной чатси совсем. Её просто небудет.

А теперь о несуществующем в Blitz3D типе double, которых бы всех спас.
Цитата:

double
Примерные приделы значений: от ±5.0 * 10^-324 до ±1.7 * 10^308 (крайние приделы по сути не имеют дробной или целой части.)
Точность: 15-16 цифр (т.е. в числе без потери точности может быть не более 15 (иногда 16, когда первая цифра "1") цифр в сумме из целой и дробной частей.)
Как мы видим уже можно использовать числа имеющие длину до 15-16 символов в строковом представлении... т.е. всреднем до 8 цифр до и после запятой.

напомню типа double нет в BlitzD, но он есть в BlitzMAX, C#, C++

ffinder 13.01.2009 12:31

Ответ: Математика в Blitz3D
 
SBJoker
молодец, правильно все объяснил.
добавлю вот что:
стек FPU 80битный, float 32бита, double - 64.
пока вычисления происходят без сохранения в память из стека FPU - точность 80битная (это правда зависит от флагов FPU). как только сохраняем значение в переменную - происходит отсечение (SBjoker об этом и сказал).

также стоит знать про машинный эпсилон (наименьшее представимое число с заданной разрядной сеткой). еще надо помнить, что формат IEEE 754 предусматривает повышение точности в области чисел в диапазоне 0..1 (хотя память мне тут может изменять, смотрите номрализованную и денормализованную форму числе с плавающей точкой).

так что не пугайтесь, когда видите, что 10.0 показывается как 9,999999. все так и зажумано:)

IGR 13.01.2009 12:41

Ответ: Математика в Blitz3D
 
impersonalis, сорри, очень бистро просмотрел пост - неувидел !!

SBJoker, спасибо за книгу !!


Часовой пояс GMT +4, время: 18:34.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot