memcmp и float
От: Аноним  
Дата: 29.08.07 18:16
Оценка:
Насколько я помню, memcmp сравнивает блоки памяти побайтно. Размер переменной типа float составляет 4 байта. Уместно ли использование memcmp для сравнения массивов типа float? Поэлементное сравнение массивов слишком уж медленное для моей ситуации. Если memcmp не подходит, кто как решал проблему производительности при сравнении массивов чисел с плавающей запятой?
Re: memcmp и float
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.08.07 18:46
Оценка:
Здравствуйте, Аноним, Вы писали:


А>Уместно ли использование memcmp для сравнения массивов типа float?


Нет. Вообще прямое сравнение чисел с плавающией запятой, вида (a==b) может дать неправильный результат
Re: memcmp и float
От: bkat  
Дата: 29.08.07 18:56
Оценка:
Здравствуйте, Аноним, Вы писали:


А>Насколько я помню, memcmp сравнивает блоки памяти побайтно. Размер переменной типа float составляет 4 байта. Уместно ли использование memcmp для сравнения массивов типа float? Поэлементное сравнение массивов слишком уж медленное для моей ситуации. Если memcmp не подходит, кто как решал проблему производительности при сравнении массивов чисел с плавающей запятой?


memcmp конечно же не подходит. Все еще сложнее.
Даже поэлементное сравнение в стиле a==b в большинстве случаев не подходят.
Сравнивать надо с некой погрешностью.
Re[2]: memcmp и float
От: Аноним  
Дата: 29.08.07 19:02
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Нет. Вообще прямое сравнение чисел с плавающией запятой, вида (a==b) может дать неправильный результат


По поводу сравнения чисел методом (a == b) согласен, вместо этого для float следует пользоваться ( fabs(a — b) < 0.0000001 )

То есть нет более быстрого способа сравнения длинных массивов чисел с плавающей запятой как поэлементное сравнение?
Re[3]: memcmp и float
От: qvasic Украина  
Дата: 29.08.07 19:27
Оценка:
А>То есть нет более быстрого способа сравнения длинных массивов чисел с плавающей запятой как поэлементное сравнение?

остается только магия
Re[4]: memcmp и float
От: Аноним  
Дата: 29.08.07 19:34
Оценка:
Здравствуйте, qvasic, Вы писали:

А>>То есть нет более быстрого способа сравнения длинных массивов чисел с плавающей запятой как поэлементное сравнение?


Q>остается только магия


вставка на ассемблере может дать заметный прирост производительности?
З.Ы. Опыта с ассемблером, к сожалению, нет, поэтому и задаю такой вопрос
Re[3]: memcmp и float
От: Uzumaki Naruto Ниоткуда  
Дата: 29.08.07 19:42
Оценка:
Не 0.0000001, а EPS — это значение определено в CRT =)

Re[4]: memcmp и float
От: Аноним  
Дата: 29.08.07 19:48
Оценка: 1 (1) +3
Здравствуйте, Uzumaki Naruto, Вы писали:

UN>Не 0.0000001, а EPS — это значение определено в CRT =)


Не EPS, а то, что тебе надо в зависимости от задачи...
Re: memcmp и float
От: Шахтер Интернет  
Дата: 29.08.07 22:38
Оценка:
Здравствуйте, Аноним, Вы писали:


А>Насколько я помню, memcmp сравнивает блоки памяти побайтно. Размер переменной типа float составляет 4 байта. Уместно ли использование memcmp для сравнения массивов типа float? Поэлементное сравнение массивов слишком уж медленное для моей ситуации. Если memcmp не подходит, кто как решал проблему производительности при сравнении массивов чисел с плавающей запятой?


Неуместно.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: memcmp и float
От: Шахтер Интернет  
Дата: 29.08.07 22:39
Оценка: 2 (2) +1 :)))
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, Аноним, Вы писали:



А>>Уместно ли использование memcmp для сравнения массивов типа float?


G>Нет. Вообще прямое сравнение чисел с плавающией запятой, вида (a==b) может дать неправильный результат


Незачет. Сравнение плавающих чисел всегда даёт правильный результат.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: memcmp и float
От: rg45 СССР  
Дата: 30.08.07 06:28
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, Аноним, Вы писали:



А>>Уместно ли использование memcmp для сравнения массивов типа float?


G>Нет. Вообще прямое сравнение чисел с плавающией запятой, вида (a==b) может дать неправильный результат


Если битовое представление a и b одинаково, то эти два числа равны и выражение a == b истинно. Если битовое представление a и b не одинаково, то эти два числа не равны и выражение a == b ложно. Исключение составляют лишь QNAN'ы, для которых по задумке число не равно само себе. Где же неправильный результат?

З.Ы. Часто случается, что при операциях с числами с плавающей точкой мы получаем результат с некоторой погрешностью и часто при сравнении эту погрешность нужно учитывать. Но сравнение дает правильный результат все-таки.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: memcmp и float
От: Erop Россия  
Дата: 30.08.07 06:53
Оценка:
Здравствуйте, Аноним, Вы писали:

А>кто как решал проблему производительности при сравнении массивов чисел с плавающей запятой?


Поясни зачем такое надо?
Может быть, например, тебе надо сравнить много-много векторов между собой? И почти все они различны?
Тогда тебе поможет такой трюк.
1) Округдляешь всё на целочисленную сетку (ну типа с фиксированной точкой)
2) Это сравниваешь быстро
3) Потом среди тех кто "примерно равен" ищешь "равных точно"
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: memcmp и float
От: alzt  
Дата: 30.08.07 07:39
Оценка:
Здравствуйте, rg45, Вы писали:

G>>Нет. Вообще прямое сравнение чисел с плавающией запятой, вида (a==b) может дать неправильный результат


R>Если битовое представление a и b одинаково, то эти два числа равны и выражение a == b истинно. Если битовое представление a и b не одинаково, то эти два числа не равны и выражение a == b ложно. Исключение составляют лишь QNAN'ы, для которых по задумке число не равно само себе. Где же неправильный результат?


R>З.Ы. Часто случается, что при операциях с числами с плавающей точкой мы получаем результат с некоторой погрешностью и часто при сравнении эту погрешность нужно учитывать. Но сравнение дает правильный результат все-таки.


Результат правильный с точке зрения эквивалентности двоичного представления, но может быть не правильным с точки зрения логики программы, как раз из-за округлений.
Re[4]: memcmp и float
От: rg45 СССР  
Дата: 30.08.07 08:03
Оценка: 4 (1)
Здравствуйте, alzt, Вы писали:

A>Здравствуйте, rg45, Вы писали:


G>>>Нет. Вообще прямое сравнение чисел с плавающией запятой, вида (a==b) может дать неправильный результат


R>>Если битовое представление a и b одинаково, то эти два числа равны и выражение a == b истинно. Если битовое представление a и b не одинаково, то эти два числа не равны и выражение a == b ложно. Исключение составляют лишь QNAN'ы, для которых по задумке число не равно само себе. Где же неправильный результат?


R>>З.Ы. Часто случается, что при операциях с числами с плавающей точкой мы получаем результат с некоторой погрешностью и часто при сравнении эту погрешность нужно учитывать. Но сравнение дает правильный результат все-таки.


A>Результат правильный с точке зрения эквивалентности двоичного представления, но может быть не правильным с точки зрения логики программы, как раз из-за округлений.


А можем ли мы в этом случае говорить, что операция сравнения дает неправильный результат? ИМХО, в этом случае правильнее говорить, что логика программы содержит ошибку, поскольку не учитывает погрешность, возможную при операциях с числами с плавающей точкой.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: memcmp и float
От: MasterZiv СССР  
Дата: 30.08.07 09:02
Оценка: 2 (1) +1
Аноним 365 пишет:
> Насколько я помню, memcmp сравнивает блоки памяти побайтно. Размер
> переменной типа float составляет 4 байта. Уместно ли использование
> memcmp для сравнения массивов типа float? Поэлементное сравнение
> массивов слишком уж медленное для моей ситуации. Если memcmp не
> подходит, кто как решал проблему производительности при сравнении
> массивов чисел с плавающей запятой?

Я считаю, что нет. На некоторых платформах число с плавающей точкой
может быть ненормализировано, и при этом два одинаковых по значению
числа будут иметь разные байтовые представления. И при сравнении
побайтно они будут разные, а фактически одинаковые.

Например, числа 1*10**2 , 100 и 0.1*10**3 одинаковые, но имеют
разное представление. Так же может быть и с двоично кодированными float.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: memcmp и float
От: Аноним  
Дата: 31.08.07 03:11
Оценка: +1
R>Если битовое представление a и b одинаково, то эти два числа равны и выражение a == b истинно. Если битовое представление a и b не одинаково, то эти два числа не равны и выражение a == b ложно. Исключение составляют лишь QNAN'ы, для которых по задумке число не равно само себе. Где же неправильный результат?

-0.0 == 0.0
Про сравнение double
От: McSeem2 США http://www.antigrain.com
Дата: 31.08.07 04:59
Оценка: 347 (43) +2
#Имя: FAQ.cpp.double==double
Здравствуйте, gandjustas, Вы писали:

G>Нет. Вообще прямое сравнение чисел с плавающией запятой, вида (a==b) может дать неправильный результат

UN>Не 0.0000001, а EPS — это значение определено в CRT =)

. . .ну и т.д.

Так. Тут начался беспредел с ужасами про сравнение плавающей точки на равенство. Требуется ликбез. Сравнивать плавающие числа (для педантов — значения переменных типа float или double) вполне можно и даже нужно. Но надо понимать сущность этой плавающей точки. А сущность заключается в том, что числа с фиксированной точкой (целые — это частный случай чисел с фиксированной точкой) имеют абсолютное значение погрешности, в отличие от чисел с плавающей точкой, где значение погрешности находится в прямой пропорциональности от модуля числа. Во всяком случае:
double a=3.1415;
double b=a;
if(a == b)
{
   . . .
}

Вот если этот if не сработает, то это означает, что компьютер сломался, а процессор издох.

Другое дело, когда числа вычислены разными способами — одно через синус, а другое — через экспоненту. Здесь действительно проверка на равенство скорее всего не сработает. Так же, как и не сработает сравнение с константой. Но это же относится и к целым числам, если скажем, мы нормализуем значения от 0...1 к 0...1000000000. То есть, не имеет значения, плавающие это числа или целые. В определенных ситуациях сравнивать их на строгое равенство нельзя. В этих ситуациях надо использовать некую Epsilon. И вот здесь-то и вылезает наружу вся безграмотность. Что такое DBL_EPSILON? — а это вот что. Это минимальное значение, которое при прибавлении его к единице, меняет значение этой единицы. Понимаете? — к единице! Строгой единице, числу 1.0 и ни к какому другому. Поэтому сравнивать числа с плавающей точкой на +/- DBL_EPSILON совершенно бессмысленно. Это сравнение выдает всю глубину невежества и неспособности думать мозгом. Факты таковы — плавающие числа больше 2.0 эту DBL_EPSILON просто не ощущают. Им что прибавляй ее, что что нет — ничего не меняет. Для этих чисел DBL_EPSILON является строгим нулем и просто не существует. В то же время, DBL_EPSILON имеет значение порядка 1e-16. Что это значит? А это значит, что числа в диапазоне Планковских масштабов (типа 1e-34) с точки зрения этой DBL_EPSILON будут все равны. То есть, эта 1e-16 становится слоном в посудной лавке. А ведь постоянная Планка ничуть не хуже скорости света — для этого собственно и были придуманы числа с плавающей точкой, чтобы отображать большие диапазоны значений с неким фиксированным количеством знаков.

Так для чего же все-таки нужна эта самая DBL_EPSILON (ну или FLT_EPSILON)? Нужна-ли? — нужна! Есть ситуации, когда действительно надо сравнивать числа в неком допустимом интервале. В каком? — А вот это как раз и зависит от абсолютного значения чисел и сущности вычислений. Короче говоря, надо эту Epsilon умножить на значение числа. А поскольку у нас два числа, то все усложняется — какое из них брать. То есть, корректное сравнение выглядит так:
if (fabs(a-b) <= DBL_EPSILON * fmax(fabs(a),fabs(b)))
{
  . . .Числа равны с относительной точностью DBL_EPSILON
}

Дорого? Да, дорого, а все остальное неправильно, такие дела. Но и это тоже неправильно! Дело в том, что этот DBL_EPSILON определяет разницу в 1 (один!) значащий бит экспоненты в приложении к числу 1.0. На практике такой разницы не встречается — числа либо строго равны, либо могут различаться больше чем на один значащий бит. Поэтому надо брать что-то типа 16*DBL_EPSILON, чтобы игнрорировать разницу в 4 младших бита (или примерно полторы последние значащие десятичные цифры из примерно 16 имеющихся).

Конечно же, есть случаи, когда диапазон чисел более-менее известен и предсказуем. Скажем, 0...1000. В этом случае, для сравнения на приблизительное равенство можно взять константу, типа 1000*16*DBL_EPSILON. Но надо иметь в виду, что такое сравнение фактически превращает всю идею плавающей точки в фиксированную точку (догадайтесь, почему).

Я вообще поражен уровню невежества — даже в весьма грамотной библиотеке GPC by Alan Murta используется тупое сравнение с константной Epsilon. На диапазонах экранных координат это все равно, что сравнение на строгое равенство, а на 1e-20 алгоритм вообще перестает работать.

И пожалуйста, имейте смелость высмеять от меня в лицо того университетского преподавателя, который скажет вам, что сравнивать плавающие числа на равенство нельзя. Такое высказывание можно простить в школе, на первом уроке информатики, но никак не в универе.

Вроде бы все сказал. Дополняйте.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[4]: memcmp и float
От: McSeem2 США http://www.antigrain.com
Дата: 31.08.07 05:10
Оценка: :)
Здравствуйте, Uzumaki Naruto, Вы писали:

UN>Не 0.0000001, а EPS — это значение определено в CRT =)


Срочно в школу! Изучать основы компьютерной грамотности.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re: memcmp и float
От: Cyberax Марс  
Дата: 31.08.07 05:29
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Насколько я помню, memcmp сравнивает блоки памяти побайтно. Размер переменной типа float составляет 4 байта. Уместно ли использование memcmp для сравнения массивов типа float? Поэлементное сравнение массивов слишком уж медленное для моей ситуации. Если memcmp не подходит, кто как решал проблему производительности при сравнении массивов чисел с плавающей запятой?

Про сравнение на равенство тебе уже тут написали

Однако, нормализованые плавающие числа без всяких там NAN'ов и прочих исключительных значений МОЖНО корректно сравнивать, используя простое побайтное сравнение. Его результат будет гарантировано правильным.
Sapienti sat!
Re[4]: memcmp и float
От: rg45 СССР  
Дата: 31.08.07 07:11
Оценка:
Здравствуйте, <Аноним>, Вы писали:

R>>Если битовое представление a и b одинаково, то эти два числа равны и выражение a == b истинно. Если битовое представление a и b не одинаково, то эти два числа не равны и выражение a == b ложно. Исключение составляют лишь QNAN'ы, для которых по задумке число не равно само себе. Где же неправильный результат?


А>-0.0 == 0.0

Если у Вас это выражение оказалось ложным, значит что-то из того, что Вы сравниваете только лишь должно быть нулем "с точки зрения логики программы", а на самом деле таковым не является. Попробуйте ради интереса откомпилировать и выполнить следующий пример:

#include<iostream>
#include<cmath>

int main() 
{
  double x = std::sin(0.0);
  double negative_x = -x;
  std::cout << (negative_x == x) << std::endl;
}


Что, неужели (negative_x == x) ложно?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[5]: memcmp и float
От: Cyberax Марс  
Дата: 31.08.07 07:13
Оценка:
Здравствуйте, rg45, Вы писали:

R>Что, неужели (negative_x == x) ложно?

Вполне может оказаться, что так. Зависит от реализации синуса.
Sapienti sat!
Re[6]: memcmp и float
От: rg45 СССР  
Дата: 31.08.07 07:21
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Здравствуйте, rg45, Вы писали:


R>>Что, неужели (negative_x == x) ложно?

C>Вполне может оказаться, что так. Зависит от реализации синуса.
Согласен, зависит. Я синус сюда влепил, чтоб помешать компилятору соптимизировать весь этот фрагмент. По смысу вместо синуса нужно подставить функцию, которая возвращает "твердый ноль". У меня синус удовлетворяет этому требованию, я рискнул предположить, что у большинства присутствующих тоже.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: memcmp и float
От: AstroMan  
Дата: 01.09.07 09:39
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>И пожалуйста, имейте смелость высмеять от меня в лицо того университетского преподавателя, который скажет вам, что сравнивать плавающие числа на равенство нельзя. Такое высказывание можно простить в школе, на первом уроке информатики, но никак не в универе.


Можно сказать проще, что все стандартные эпсилоны относятся только к мантиссе числа. В большинстве задач надо вводить погрешность из проблемной области (например, 0.001 см для разметки текста на странице или 1.0E+30 г для массы звезд).
Re[3]: memcmp и float
От: Шахтер Интернет  
Дата: 02.09.07 01:49
Оценка:
Здравствуйте, McSeem2, Вы писали:

Сравнивать плавающие числа или не сравнивать и как именно -- зависит исключительно о решаемой задачи. Вне конкретного контекста обсуждать можно лишь свойства примитивных опрераций -- в данном случае операции сравнения.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: memcmp и float
От: Шахтер Интернет  
Дата: 02.09.07 01:50
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Здравствуйте, Аноним, Вы писали:


А>>Насколько я помню, memcmp сравнивает блоки памяти побайтно. Размер переменной типа float составляет 4 байта. Уместно ли использование memcmp для сравнения массивов типа float? Поэлементное сравнение массивов слишком уж медленное для моей ситуации. Если memcmp не подходит, кто как решал проблему производительности при сравнении массивов чисел с плавающей запятой?

C>Про сравнение на равенство тебе уже тут написали

C>Однако, нормализованые плавающие числа без всяких там NAN'ов и прочих исключительных значений МОЖНО корректно сравнивать, используя простое побайтное сравнение. Его результат будет гарантировано правильным.


+0 -0
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[3]: memcmp и float
От: Шахтер Интернет  
Дата: 02.09.07 01:53
Оценка:
Здравствуйте, rg45, Вы писали:

R>Если битовое представление a и b не одинаково, то эти два числа не равны и выражение a == b ложно.


Это не так. Есть +0 и -0, есть так же ненормализованные числа.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: memcmp и float
От: McSeem2 США http://www.antigrain.com
Дата: 02.09.07 20:58
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Сравнивать плавающие числа или не сравнивать и как именно -- зависит исключительно о решаемой задачи. Вне конкретного контекста обсуждать можно лишь свойства примитивных опрераций -- в данном случае операции сравнения.


Безусловно. Но надо иметь хотя бы начальную печку, от которой танцевать. А то так и будут писать ахинею типа if(fabs(a-b) <= DBL_EPSILON)...
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[4]: memcmp и float
От: McSeem2 США http://www.antigrain.com
Дата: 02.09.07 21:01
Оценка:
Здравствуйте, AstroMan, Вы писали:

AM>Можно сказать проще, что все стандартные эпсилоны относятся только к мантиссе числа. В большинстве задач надо вводить погрешность из проблемной области (например, 0.001 см для разметки текста на странице или 1.0E+30 г для массы звезд).


Я специально написал такой развернутый ответ, за еще и "с эмоциями". Сказать проще конечно можно, но это увы не наглядно и часто не доходит.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[3]: memcmp и float
От: Cyberax Марс  
Дата: 02.09.07 21:15
Оценка:
Здравствуйте, Шахтер, Вы писали:

C>>Однако, нормализованые плавающие числа без всяких там NAN'ов и прочих исключительных значений МОЖНО корректно сравнивать, используя простое побайтное сравнение. Его результат будет гарантировано правильным.

Ш>+0 -0
-0 < +0, AFAIR. А что ты хотел?
Sapienti sat!
Re[3]: memcmp и float
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 16.12.07 07:58
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>И пожалуйста, имейте смелость высмеять от меня в лицо того университетского преподавателя, который скажет вам, что сравнивать плавающие числа на равенство нельзя. Такое высказывание можно простить в школе, на первом уроке информатики, но никак не в универе.


Я всё-таки на это возражу:)) Дело в том, что в вычислительном алгоритме ситуаций, которые достаточно просто сводятся к

  double b = a;
  if (a != b) { шеф, усё пропало! }


крайне мало — я бы сказал, что их вообще не бывает.

А вот ситуаций, когда пишут код вида

  for(double x = 0.0; x <= 20.0; x += 0.1) {
    ...
  }


много — фактически, каждому хотя бы раз приходилось писать такое (и потом удивляться результату — а куда делась последняя итерация?)

Именно поэтому устанавливать принцип "не сравнивайте на точное равенство! всегда сравнивайте величину разницы" вместе с некоторыми простыми советами типа "замените x<=20.0 на x<=20.5" имеет право на жизнь и тем более в университете. А ещё есть конверсии, когда double где-то был перенесен во float, а потом обратно... Найти случаи, когда надо сравнивать более просто, грамотный программист сможет — а если не сможет, ему вообще в вычислительной математике делать нечего. А вот сделать, чтобы правильное сравнение вошло "в плоть и кровь" — преподаватель таки должен.

По поводу вот этого:

MS> Конечно же, есть случаи, когда диапазон чисел более-менее известен и предсказуем. Скажем, 0...1000. В этом случае, для сравнения на приблизительное равенство можно взять константу, типа 1000*16*DBL_EPSILON. Но надо иметь в виду, что такое сравнение фактически превращает всю идею плавающей точки в фиксированную точку (догадайтесь, почему).


До определённой степени та же "фиксированная точка" тут совсем неплоха. По крайней мере при сравнении. Только, наверно, не при 0...1000, а хотя бы при 10...1000. Общих рецептов всё равно не будет, в вычислительной математике огромное количество тонкостей, зависящих и от специфики исходной задачи... я когда-то наигрался с этим.
The God is real, unless declared integer.
Re[5]: memcmp и float
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 16.12.07 07:59
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, Шахтер, Вы писали:


Ш>>Сравнивать плавающие числа или не сравнивать и как именно -- зависит исключительно о решаемой задачи. Вне конкретного контекста обсуждать можно лишь свойства примитивных опрераций -- в данном случае операции сравнения.


MS>Безусловно. Но надо иметь хотя бы начальную печку, от которой танцевать. А то так и будут писать ахинею типа if(fabs(a-b) <= DBL_EPSILON)...


Вот с этим полностью согласен. (Пишу это явно на всякий случай)
The God is real, unless declared integer.
Re[4]: memcmp и float
От: McSeem2 США http://www.antigrain.com
Дата: 17.12.07 16:50
Оценка: 16 (3) +2
Здравствуйте, netch80, Вы писали:

N>Я всё-таки на это возражу Дело в том, что в вычислительном алгоритме ситуаций, которые достаточно просто сводятся к


N>
N>  double b = a;
N>  if (a != b) { шеф, усё пропало! }
N>


N>крайне мало — я бы сказал, что их вообще не бывает.


Бывает и довольно много, по крайней мере в моей практике. Например, восстановить связность графа по набору ребер и координатам их концов. Вполне практическая задача, необходимая для растеризации данных из Flash. Вообще, в вычислительной геометрии встречается сплошь и рядом.

N>А вот ситуаций, когда пишут код вида


N>
N>  for(double x = 0.0; x <= 20.0; x += 0.1) {
N>    ...
N>  }
N>


N>много — фактически, каждому хотя бы раз приходилось писать такое (и потом удивляться результату — а куда делась последняя итерация?)


Это несколько другой эффект, связанный с невозможностью точного представления десятичных дробей в двоичном виде. Числа 0.1 в двоичном виде не существует. Вышеуказанный цикл может сработать неправильно даже с фиксированной точкой. Здесь главным условием является наличие десятичной дроби (причем, не всякой), представленной в двоичном виде. Например, при обработке в BCD все сработает нормально. В случае с таким циклом надо именно что разъяснить студентам этот побочный эффект на как можно более ранних стадиях. Например:

  for(double x = 0.0; x <= 20.0; x += 0.1) {  // неправильно
    ...
  }

  for(double x = 0.0; x <= 200.0; x += 1.0) {  // правильно
    ...
  }

  for(double x = 0.0; x <= 100.0; x += 0.5) {  // правильно
    ...
  }


Другими словами, требуется обеспечить понимание, что некоторые десятичные дроби не имеют точного представления в двоичном виде.

Так называемые практические советы, типа "x <= 20.05" опасны, поскольку могут только запутать и сбить с толку. И главное — они лечат симптом, а не болезнь, еще больше отдаляя понимание сущности. Вот после того, как наступило понимание, можно дать подобный совет, но не раньше. Но при этом и надобность в подобном совете отпадает — человек уже понимает сущность и сам сообразит что к чему.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[4]: memcmp и float
От: McSeem2 США http://www.antigrain.com
Дата: 17.12.07 17:26
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Это не так. Есть +0 и -0, есть так же ненормализованные числа.


Раз уж подняли тему, то что это за зверь такой, ненормализованные числа? Ведь при нормальных условиях, float и double всегда нормализованы. Они просто не могут быть ненормализованными, поскольку старший разряд мантиссы не хранится, а только лишь подразумевается, поскольку он всегда равен 1. Ненормализованными являются только числа с минимально возможным значением порядка, для float — меньше 1.2e-38. Но это уже такой экстрим, до которого лучше не доводить. И AFAIK, не все архитектуры правильно понимают ненормализованные числа — можно нарваться на несовместимость при передаче данных.

Исключительной ситуацией при нормальных условиях является только +0, -0, если всякие inf, NaN рссмативать как ошибочные ситуации. Но и +0, -0 — это явление того же порядка, что и сравнение в доверительном интервале — если числа получены одинаковым способом, их битовые значения должны быть строго равны. С этой точки зрения, при определенных ограничениях побитовое сравнение сработает точно так же, как и сравнение на равенство и, следовательно, вполне уместно. Необходимо только четко понимать эти ограничения.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[5]: memcmp и float
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 17.12.07 17:48
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, Шахтер, Вы писали:


Ш>>Это не так. Есть +0 и -0, есть так же ненормализованные числа.


MS>Раз уж подняли тему, то что это за зверь такой, ненормализованные числа? Ведь при нормальных условиях, float и double всегда нормализованы. Они просто не могут быть ненормализованными, поскольку старший разряд мантиссы не хранится, а только лишь подразумевается, поскольку он всегда равен 1.


В форматах IEEE754 — да. Но если Вы думаете, что ими ограничивается мир, то ошибаетесь.:)
Даже в x87 во внутреннем 80-битном представлении старший разряд мантиссы хранится явно и может быть 0. А на других платформах — тем более. На S/360 вообще были разные команды для вычислений с нормализацией результата и без оной.
The God is real, unless declared integer.
Re[2]: memcmp и float
От: McSeem2 США http://www.antigrain.com
Дата: 18.12.07 15:17
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Я считаю, что нет. На некоторых платформах число с плавающей точкой

MZ>может быть ненормализировано, и при этом два одинаковых по значению
MZ>числа будут иметь разные байтовые представления. И при сравнении
MZ>побайтно они будут разные, а фактически одинаковые.

Если речь идет о float/double в формате IEEE754, то числа там всегда нормализованные, за исключением клинических случаев, типа 1e-40 для 32-битового float.

MZ>Например, числа 1*10**2 , 100 и 0.1*10**3 одинаковые, но имеют

MZ>разное представление. Так же может быть и с двоично кодированными float.

Не может. Дело в том, что во float в принципе невозможно представить ненормализованное число. Это обусловлено экономией одного бита. В нормализованном числе (в двоичном представлении, конечно же) старший бит мантиссы всегда равен единице. Следовательно, его можно не хранить, а только подразумевать. Например, двоичное представление 0.00101 будет воспринято как нормализованное 0.100101. В конце концов, возьмите число 1.0 и посмотрите, чему равна его мантисса — она равна нулю.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[3]: memcmp и float
От: Аноним  
Дата: 19.03.08 03:39
Оценка:
Из всего здесь сказанного я понял что стратегия сравнения ЧСПТ зависит от проблемы над которой идет работа.
Но вот простое сравнене синуса 90.0 и косинуса 0.0 без привязки к конкретной проблемной области не получается (VS2003):

sin(90.0) = 0.999999999999999
cos(0.0) = 1
abs(cos(0.0) — sin(90.0)) = 9.992007221626409e-016
>
std::numeric_limits<double>::epsilon() = 2.220446049250313e-016
Re[3]: memcmp и float
От: Vamp Россия  
Дата: 19.03.08 07:43
Оценка:
Ш>Незачет. Сравнение плавающих чисел всегда даёт правильный результат.
Вообще-то мне в жизни не доводилось встречать плавающих чисел. БДывали плавающие рыбы, плавающие животные, даже плавающие птицы бывают... А чисел не видал.
Да здравствует мыло душистое и веревка пушистая.
Re[5]: memcmp и float
От: s_viy  
Дата: 20.03.08 08:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, qvasic, Вы писали:


А>>>То есть нет более быстрого способа сравнения длинных массивов чисел с плавающей запятой как поэлементное сравнение?


Q>>остается только магия


А>вставка на ассемблере может дать заметный прирост производительности?

А>З.Ы. Опыта с ассемблером, к сожалению, нет, поэтому и задаю такой вопрос

Опыта тоже нет, но работал с проектом где для перебора и сравнения элементов использовался ассемблер, что давало существенный прирост производительности. Однако это имеет смысл только при использовании каких-то специальных инструкций процессора, о которых компилятор не знает. А в общем случае он сгенерит код не хуже чем ты сам напишешь.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.