PDA

Просмотр полной версии : Баг с простыми арифметическими действиями (приведение типов)?


wvxvw
06.02.2008, 18:47
class rendering.Line {

private var __a:PNT;
private var __b:PNT;

private var __length:Number = Number.NaN;
private var __height:Number = Number.NaN;
private var __width:Number = Number.NaN;
private var __angle:Number = Number.NaN;

public function Line(pa:PNT, pb:PNT) {
__a = pa;
__b = pb;
__width = __b.x - __a.x;
__height = __b.y - __a.y;
trace(pa.x + ' : ' + pa.y + ' : ' + pb.x + ' : ' + pb.y);
trace(__b.x == __a.x);
trace('angle: ' + __angle + ' : ' + __height + ' : ' + __width);
__length = Math.sqrt(__width * __width + __height * __height);
__angle = Math.atan(__width / __height);
}
}
class rendering.PNT extends Array {

public function PNT(xx:Number, yy:Number) {
this.push(xx);
this.push(yy);
}

public function set x(p:Number):Void {
this[0] = Math.round(p);
}
public function get x():Number {
return this[0];
}
public function set y(p:Number):Void {
this[1] = Math.round(p);
}
public function get y():Number {
return this[1];
}
}

Похоже на баг компайлера... или я чего-то не понимаю =/

Уже чего только не делал...
new Line(new PNT(130,130), new PNT(30,130));
И в трейс выдается:
angle: NaN : -2.8421709430404e-14 : -100
(вместо -2.8421709430404e-14 должно быть 0)

iNils
06.02.2008, 18:59
Мой трейс
130 : 130 : 30 : 130
false
angle: NaN : 0 : -100

MrPoma
06.02.2008, 19:08
опустите трейс в низ конструктора и будет вам сказка

в результате трейс:
130 : 130 : 30 : 130
false
angle: -1.5707963267949 : 0 : -100

wvxvw
06.02.2008, 19:14
Перезапустил комп... откомпилировал флешем и мтаском... по прежнему такой же результат... Самое непонятное, что с некоторыми числами проблем не возникает =/

опустите трейс в низ конструктора и будет вам сказка

в результате трейс:
А при чем то, где находится трейс? Мне угол не интересен... Плохо то, что 130-130 почему-то получается -2.8421709430404e-14, а не 0...

iNils
06.02.2008, 19:22
Числа которые передавались в "new Line(new PNT(..." были получены в результате неких мат операций, но для примера ты вывел их в трейс и дал их нам, а сам продолжаешь использовать результаты мат операций?

chingachgoog
06.02.2008, 19:25
Плохо то, что 130-130 почему-то получается -2.8421709430404e-14, а не 0...

Мантисса 15 знаков...


Если не знать особенностей представления чисел на компьютере, то возможны очень интересные сюрпризы. Например, попробуем вычислить значения двух алгебраически абсолютно идентичных выражений и посмотрим, совпадут ли результаты:

var a=500000;
var expr1=a/(Math.pow(a+1,1/2)+Math.pow(a,1/2));
var expr2=a*(Math.pow(a+1,1/2)-Math.pow(a,1/2));
trace(expr1-expr2); // Выводит: 3.72591557606938e-9

Результаты расчетов по двум идентичным формулам различаются, пусть и не значительно.Аэто означает, что если бымыпытались установить факт равенства этих выражений, используя предложение if(), то вывод был бы сделан неверно, что связано с тем, что в ActionScript два числа равны только тогда, когда равенство соблюдается для всех разрядов.
Причиной появления ошибок, подобных описанной, является то, что числа сохраняются с ограниченной точностью. Конечно, 15 знаков мантиссы достаточно для большинства расчетов. Но в некоторых случаях ошибки округления способны накапливаться, искажая результат весьма значительно.

Особый случай представляют встроенные тригонометрические функции, результаты вычислений значений которых в точках нулей и разрывов практически никогда не совпадают с математически верными:

trace(Math.sin(Math.PI)); // Выводит: 1.22460635382238e-16 (нужно -0)
trace(Math.tan(Math.PI/2)); // Выводит: 1.63317787283838e+16 (нужно —
// Infinity)

Причиной появления не совсем правильных результатов в приведенных примерах является округление мантиссы чисел до 15 знаков. Справиться с этой проблемой непосредственным образом невозможно.

iNils
06.02.2008, 19:36
chingachgoog, дело не в этом, а в том, что в трейс идет число округленное, а в расчетах участвует дробное.
Вот пример где после запятой всего 13 знаков.
a = 130;
b = 130;
d = b + 0.0000000000001;
trace (d + " - " + a + " = " + (d - a));
и результат
130 - 130 = 1.13686837721616e-13

2 wvxvw: в классе PNT для сеттеров стоит округление для вновь вводимых значениях, а в конструкторе - нет.

wvxvw
06.02.2008, 19:40
Ой... всем спасибо =) Нужно было в геттере округлять, а не в сеттере... невнимательность

iNils
06.02.2008, 19:46
Ой... всем спасибо =) Нужно было в геттере округлять, а не в сеттере... невнимательностьЯ бы оставил в сеттере, вместо того, чтобы при каждов запросе делать округление повторно, что явно производительности не прибавит. И в конструкторе бы округление сделал.

...однако мне не понятно, что было расширять здесь Array, когда нужно расширить Point.

wvxvw
06.02.2008, 20:32
С первым согласен, да, правельнее будет в конструкторе округлить.
А массив - потому что в других местах понадобятся некоторые его свойства, типа конкантенации, например. А в Point есть куча всего, что я не собираюсь использовать.

iNils
06.02.2008, 20:45
А в Array все будешь использовать? Ты только с собой кучу "мусора" таскать будешь. Надо в таких случаи наследовать от Object.

wvxvw
06.02.2008, 21:32
Тут на самом деле есть еще такой момент... возможно, чушь, но вроде где-то слышал, что обращение по цифровому индексу быстрее, чем по имени... а тут скорее это будет важно, а не объем занятой памяти...

iNils
06.02.2008, 21:51
То есть, ты гдето слышал, сам не проверял, но решил использовать?:)

wvxvw
06.02.2008, 23:06
Именно %)
Ну я только начал, проверять позже буду, в принципе, переписать такой класс займет ровно минуту, если увижу, что это чушь - так и переделаю =)

Вот, только что попробовал, оказалось, наоборот %)