Сравнение float
От: Yuri Россия http://spbdetails.ru
Дата: 19.02.02 16:07
Оценка:
Привет всем!
Есть два числа типа float,
одно содержит 0.50000002607703
другое — 0.50000000000000
Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой
Take it easy.
Re: Сравнение float
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 19.02.02 16:24
Оценка:
Здравствуйте Yuri, Вы писали:

Y>Привет всем!

Y>Есть два числа типа float,
Y>одно содержит 0.50000002607703
Y>другое — 0.50000000000000
Y>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

Первое, что приходит в голову — умножить на 100 (на 10 в степени кол-ва нуждных тебе разрядов, в этом случае — 2). и отбросить дробную часть, и сравнить. Или, после умножения вычесть меньшее из большего, и сравнить разность. Если она меньше единицы — все хорошо, это оно.

С уважением
Алексей Кирдин
Re[2]: Сравнение float
От: Sergey Россия  
Дата: 19.02.02 16:36
Оценка:
Здравствуйте Kaa, Вы писали:

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


Y>>Привет всем!

Y>>Есть два числа типа float,
Y>>одно содержит 0.50000002607703
Y>>другое — 0.50000000000000
Y>>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

Kaa>Первое, что приходит в голову — умножить на 100 (на 10 в степени кол-ва нуждных тебе разрядов, в этом случае — 2). и отбросить дробную часть, и сравнить.

Так делать нельзя. Например, сравни 2.9999999999 и 3.000000000

Kaa>Или, после умножения вычесть меньшее из большего, и сравнить разность. Если она меньше единицы — все хорошо, это оно.


А вот это уже правильно, только умножать незачем — вычесть, сравнить с допустимой ошибкой.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: Сравнение float
От: Кодт Россия  
Дата: 19.02.02 16:36
Оценка:
Здравствуйте Yuri, Вы писали:

Y>Привет всем!

Y>Есть два числа типа float,
Y>одно содержит 0.50000002607703
Y>другое — 0.50000000000000
Y>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

Округлить ;)

1) округление до 0.01

inline double round_to(double value, double eps)
{
  assert(eps > 0);
  return floor(value/eps + 0.5) * eps;
}

inline int compare_1(double a, double b, double eps)
{
  double diff = floor(a/eps + 0.5) - floor(b/eps + 0.5);
  return diff < 0 ? -1 : diff > 0 ? +1 : 0;
}

compare_1(0.5123, 0.5145, 0.01);

diff = floor(51.23 + 0.5) - floor(51.45 + 0.5) == 51-51 = 0


2) числа в окрестности +/- 1% считать равными

inline double compare_2(double a, double b, double eps)
{
  double diff = round_to( (a - b) * 2 / (a + b), eps);
  return diff < 0 ? -1 : diff > 0 ? +1 : 0;
}

compare_2(0.000512, 0.000534, 0.01)

diff = round_to( -0.000022 / 0.000522, 0.01 )
     = round_to( -0.0421..., 0.01 )
     = -0.04

compare_2(0.0005123, 0.0005145, 0.01)

diff = round_to( -0.0000022 / 0.0005122, 0.01 )
     = round_to( -0.00429..., 0.01 )
     = 0
Перекуём баги на фичи!
Re[3]: Сравнение float
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 19.02.02 16:42
Оценка:
Здравствуйте Sergey, Вы писали:

Чего к словам придираться. Все всё поняли. Дело в алгоритме.

Kaa>>Первое, что приходит в голову — умножить на 100 (на 10 в степени кол-ва нуждных тебе разрядов, в этом случае — 2). и отбросить дробную часть, и сравнить.

S> Так делать нельзя. Например, сравни 2.9999999999 и 3.000000000
299.0 != 300.0, что и требовалось доказать. Что не так? В чем "нельзя"?

Kaa>>Или, после умножения вычесть меньшее из большего, и сравнить разность. Если она меньше единицы — все хорошо, это оно.


S> А вот это уже правильно, только умножать незачем — вычесть, сравнить с допустимой ошибкой.


Можно и не умножать. Тогда погрешность (допустимую ошибку) знать надо.

С уважением
Алексей Кирдин
Re[4]: Сравнение float
От: Sergey Россия  
Дата: 19.02.02 16:54
Оценка:
Здравствуйте Kaa, Вы писали:

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


Kaa>Чего к словам придираться. Все всё поняли. Дело в алгоритме.


Kaa>>>Первое, что приходит в голову — умножить на 100 (на 10 в степени кол-ва нуждных тебе разрядов, в этом случае — 2). и отбросить дробную часть, и сравнить.

S>> Так делать нельзя. Например, сравни 2.9999999999 и 3.000000000
Kaa>299.0 != 300.0, что и требовалось доказать. Что не так? В чем "нельзя"?

Ты всерьез полагаешь, что человеку надо именно это — два числа, отличающиещиеся на 0.0е-10, считать разными? Если да, то можно просто битмаской лишнее прихлопнуть (сколько там двоичных знаков, сразу и не соображу) и сравнивать — будет типа очень быстро

Kaa>>>Или, после умножения вычесть меньшее из большего, и сравнить разность. Если она меньше единицы — все хорошо, это оно.


S>> А вот это уже правильно, только умножать незачем — вычесть, сравнить с допустимой ошибкой.


Kaa>Можно и не умножать. Тогда погрешность (допустимую ошибку) знать надо.


Kaa>С уважением
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: Сравнение float
От: Курилка Россия http://kirya.narod.ru/
Дата: 19.02.02 17:04
Оценка: +1
Здравствуйте Yuri, Вы писали:

Y>Привет всем!

Y>Есть два числа типа float,
Y>одно содержит 0.50000002607703
Y>другое — 0.50000000000000
Y>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

я дак делаю fabs(val1-val2)<delta, что даёт условие равенства, а неравенства дальше сами разрешаются.
где delta — необходимая точность
Re[5]: Сравнение float
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 19.02.02 17:11
Оценка:
Здравствуйте Sergey, Вы писали:

S> Ты всерьез полагаешь, что человеку надо именно это — два числа, отличающиещиеся на 0.0е-10, считать разными? Если да, то можно просто битмаской лишнее прихлопнуть (сколько там двоичных знаков, сразу и не соображу) и сравнивать — будет типа очень быстро

Вопрос перечитай, что-ли. Ему надо, в твоих терминах, отождествить 2 числа с одинаковыми первыми тремя разрядами при равным показателем степени в стандартной заприси числа.

С уважением
Алексей Кирдин
Re[6]: Сравнение float
От: Sergey Россия  
Дата: 20.02.02 08:04
Оценка:
Здравствуйте Kaa, Вы писали:

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


S>> Ты всерьез полагаешь, что человеку надо именно это — два числа, отличающиещиеся на 0.0е-10, считать разными? Если да, то можно просто битмаской лишнее прихлопнуть (сколько там двоичных знаков, сразу и не соображу) и сравнивать — будет типа очень быстро

Kaa>Вопрос перечитай, что-ли. Ему надо, в твоих терминах, отождествить 2 числа с одинаковыми первыми тремя разрядами при равным показателем степени в стандартной заприси числа.

Перечитал. По вопросу совершенно непонятно, что ж ему все-таки надо. Так что если ему это еще надо, пусть задает вопрос по новой
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[2]: Сравнение float
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 20.02.02 13:18
Оценка:
Здравствуйте Курилка, Вы писали:

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


Y>>Привет всем!

Y>>Есть два числа типа float,
Y>>одно содержит 0.50000002607703
Y>>другое — 0.50000000000000
Y>>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

К>я дак делаю fabs(val1-val2)<delta, что даёт условие равенства, а неравенства дальше сами разрешаются.

К>где delta — необходимая точность

Это немного не то. Вот тебе пример:
2.99092 -> 2.99 != 3.00 -> 3.00, хотя при этом |2.99092 — 3.00| < 0.01
Короче говоря, требуется совпадение разрядов, а не просто их близость на числовой прямой.

С уважением
Алексей Кирдин
Re[3]: Сравнение float
От: Курилка Россия http://kirya.narod.ru/
Дата: 20.02.02 13:38
Оценка:
Здравствуйте Kaa, Вы писали:

Kaa>Здравствуйте Курилка, Вы писали:


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


Y>>>Привет всем!

Y>>>Есть два числа типа float,
Y>>>одно содержит 0.50000002607703
Y>>>другое — 0.50000000000000
Y>>>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой

К>>я дак делаю fabs(val1-val2)<delta, что даёт условие равенства, а неравенства дальше сами разрешаются.

К>>где delta — необходимая точность

Kaa>Это немного не то. Вот тебе пример:

Kaa>2.99092 -> 2.99 != 3.00 -> 3.00, хотя при этом |2.99092 — 3.00| < 0.01
Kaa>Короче говоря, требуется совпадение разрядов, а не просто их близость на числовой прямой.

И кому такое сравнение нужно??? Стесняюсь спросить...

тогда и 2.9901 будет равно 3.0099?
по-моему для нормальной задачи это бред
Re[4]: Сравнение float
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 20.02.02 13:45
Оценка: 1 (1)
Здравствуйте Курилка, Вы писали:

Y>>>>Привет всем!

Y>>>>Есть два числа типа float,
Y>>>>одно содержит 0.50000002607703
Y>>>>другое — 0.50000000000000
Y>>>>Как мне их сравнить, так чтобы в сравнении участвовали только две цифры после запятой
Это видел?

Kaa>>Это немного не то. Вот тебе пример:

Kaa>>2.99092 -> 2.99 != 3.00 -> 3.00, хотя при этом |2.99092 — 3.00| < 0.01
Kaa>>Короче говоря, требуется совпадение разрядов, а не просто их близость на числовой прямой.

К>И кому такое сравнение нужно??? Стесняюсь спросить...

Ему нужно, спрашивающему.

К>тогда и 2.9901 будет равно 3.0099?

Когда — "тогда". Отождествляются только чиса с первыми тремя разрядами. В твоем примере это не так. Разряды различаются. Так, напимер, можно сравнивать деньги: целые — рубли, дробные — копейки. Без большой точности. Это, ты считаешь, не реальная задача? )

С уважением
Алексей Кирдин
Re[5]: Сравнение float
От: Курилка Россия http://kirya.narod.ru/
Дата: 20.02.02 13:51
Оценка:
Здравствуйте Kaa, Вы писали:
К>>тогда и 2.9901 будет равно 3.0099?
Kaa>Когда — "тогда". Отождествляются только чиса с первыми тремя разрядами. В твоем примере это не так. Разряды различаются.

сорри, я имел в виду 2.9999 != 3.00
вечно пишу совсем не то, что думаю

Kaa>Так, напимер, можно сравнивать деньги: целые — рубли, дробные — копейки. Без большой точности. Это, ты считаешь, не реальная задача? )


наверно ты прав, хотя на мой взгляд это тоже спорно, как деньги округлять...
Re[6]: Сравнение float
От: Кодт Россия  
Дата: 21.02.02 10:16
Оценка:
Здравствуйте Курилка, Вы писали:

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

К>>>тогда и 2.9901 будет равно 3.0099?
Kaa>>Когда — "тогда". Отождествляются только чиса с первыми тремя разрядами. В твоем примере это не так. Разряды различаются.

К>сорри, я имел в виду 2.9999 != 3.00

К>вечно пишу совсем не то, что думаю

Kaa>>Так, напимер, можно сравнивать деньги: целые — рубли, дробные — копейки. Без большой точности. Это, ты считаешь, не реальная задача? )


К>наверно ты прав, хотя на мой взгляд это тоже спорно, как деньги округлять...


На самом деле задача встречается весьма часто.
  • накопление ошибок в вычислениях (тривиальный случай 1/3*3 = 0.3333*3 = 0.9999 отрабатывается мат.процессором, но вообще несложно накопить ошибку в последнем разряде, а потом ее "усилить" до значимых)
  • в графике: если печать 300 dpi, соответственно точки на расстоянии < 1/12 мм не должны различаться.
  • снятие показаний с аналоговых устройств
  • цифровые фильтры
  • Перекуём баги на фичи!
    Re[7]: Сравнение float
    От: Sergey Россия  
    Дата: 21.02.02 10:39
    Оценка: 1 (1)
    Здравствуйте Кодт, Вы писали:

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


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

    К>>>>тогда и 2.9901 будет равно 3.0099?
    Kaa>>>Когда — "тогда". Отождествляются только чиса с первыми тремя разрядами. В твоем примере это не так. Разряды различаются.

    К>>сорри, я имел в виду 2.9999 != 3.00

    К>>вечно пишу совсем не то, что думаю

    Kaa>>>Так, напимер, можно сравнивать деньги: целые — рубли, дробные — копейки. Без большой точности. Это, ты считаешь, не реальная задача? )


    К>>наверно ты прав, хотя на мой взгляд это тоже спорно, как деньги округлять...


    К>На самом деле задача встречается весьма часто.

    К>
  • накопление ошибок в вычислениях (тривиальный случай 1/3*3 = 0.3333*3 = 0.9999 отрабатывается мат.процессором, но вообще несложно накопить ошибку в последнем разряде, а потом ее "усилить" до значимых)

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

    К>
  • в графике: если печать 300 dpi, соответственно точки на расстоянии < 1/12 мм не должны различаться.

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

    К>
  • снятие показаний с аналоговых устройств

    Ну и зачем тут может понадобиться отбрасывать значения младших разрядов?

    К>
  • цифровые фильтры

    А вот это, конечно, дело темное Но, опять же, нафига в них сравнивать числа, отбрасывая младшие разряды? Разве что для скорости...
  • Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
    Re[8]: Сравнение float
    От: Кодт Россия  
    Дата: 24.02.02 13:08
    Оценка:
    Здравствуйте Sergey, Вы писали:

    К>>
  • накопление ошибок в вычислениях (тривиальный случай 1/3*3 = 0.3333*3 = 0.9999 отрабатывается мат.процессором, но вообще несложно накопить ошибку в последнем разряде, а потом ее "усилить" до значимых)

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


    Банковское округление — это, грубо говоря, 0.04 --> 0.0, 0.05 --> 0.1,
    т.е. ошибка составляет 0.05 вместо 0.10. Тем не менее, она накапливается.

    К>>
  • в графике: если печать 300 dpi, соответственно точки на расстоянии < 1/12 мм не должны различаться.

    S> Вот именно, при этом точки 0.9999999 и 1.0000000 различаться не должны. Так что тут не разряды сравниваются.


    К>>
  • снятие показаний с аналоговых устройств

    S> Ну и зачем тут может понадобиться отбрасывать значения младших разрядов?


    Например, соотношение сигнал/шум составляет 1:0.01.
    Какой тогда смысл снимать с АЦП больше 2 разрядов?

    "Шум" может быть как внешний (подмешанный к сигналу), так и внутренний (точность самого прибора).

    К>>
  • цифровые фильтры

    S> А вот это, конечно, дело темное Но, опять же, нафига в них сравнивать числа, отбрасывая младшие разряды? Разве что для скорости...


    Это не просто отбрасывание. Это сглаживание.
  • Перекуём баги на фичи!
    Re[9]: Сравнение float
    От: Sergey Россия  
    Дата: 26.02.02 09:25
    Оценка: 10 (1)
    Здравствуйте Кодт, Вы писали:

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


    К>>>
  • накопление ошибок в вычислениях (тривиальный случай 1/3*3 = 0.3333*3 = 0.9999 отрабатывается мат.процессором, но вообще несложно накопить ошибку в последнем разряде, а потом ее "усилить" до значимых)

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


    К>Банковское округление — это, грубо говоря, 0.04 --> 0.0, 0.05 --> 0.1,

    К>т.е. ошибка составляет 0.05 вместо 0.10. Тем не менее, она накапливается.

    Не, не так прямолинейно. "Банковское округление" — это, например (есть, вроде бы, несколько способов) когда 1.05 -> 1.1,
    а 2.05 -> 2.0. Если сумма цифр четная и последняя цифра — пятерка, округляем в одну сторону, нечетная — в другую. Ошибка не накапливается, если числа можно считать случайными.

    К>>>
  • в графике: если печать 300 dpi, соответственно точки на расстоянии < 1/12 мм не должны различаться.

    S>> Вот именно, при этом точки 0.9999999 и 1.0000000 различаться не должны. Так что тут не разряды сравниваются.


    К>>>
  • снятие показаний с аналоговых устройств

    S>> Ну и зачем тут может понадобиться отбрасывать значения младших разрядов?


    К>Например, соотношение сигнал/шум составляет 1:0.01.

    К>Какой тогда смысл снимать с АЦП больше 2 разрядов?

    IMHO (потому что лень считать), если ограничиться двумя разрядами, соотношение сигнал/шум будет хуже. Сложится (среднеквадратично) шум квантования и помеха.

    К>"Шум" может быть как внешний (подмешанный к сигналу), так и внутренний (точность самого прибора).


    К>>>
  • цифровые фильтры

    S>> А вот это, конечно, дело темное Но, опять же, нафига в них сравнивать числа, отбрасывая младшие разряды? Разве что для скорости...


    К>Это не просто отбрасывание. Это сглаживание.


    Можно поподробнее? Что и как тут сглаживается (чем отбрасывание лучше сглаживания, если не принимать в расчет быстродействие)?
  • Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
    Re[10]: Сравнение float
    От: Кодт Россия  
    Дата: 26.02.02 13:02
    Оценка:
    Здравствуйте Sergey, Вы писали:

    К>>Банковское округление — это, грубо говоря, 0.04 --> 0.0, 0.05 --> 0.1,

    К>>т.е. ошибка составляет 0.05 вместо 0.10. Тем не менее, она накапливается.

    S> Не, не так прямолинейно. "Банковское округление" — это, например (есть, вроде бы, несколько способов) когда 1.05 -> 1.1,

    S>а 2.05 -> 2.0. Если сумма цифр четная и последняя цифра — пятерка, округляем в одну сторону, нечетная — в другую. Ошибка не накапливается, если числа можно считать случайными.

    А если не случайными?

    К>>>>
  • снятие показаний с аналоговых устройств

    S>>> Ну и зачем тут может понадобиться отбрасывать значения младших разрядов?


    К>>Например, соотношение сигнал/шум составляет 1:0.01.

    К>>Какой тогда смысл снимать с АЦП больше 2 разрядов?

    S> IMHO (потому что лень считать), если ограничиться двумя разрядами, соотношение сигнал/шум будет хуже. Сложится (среднеквадратично) шум квантования и помеха.


    Да, насчет шума квантования — недодумал.
    Вычисления — пожалуйста, с большой точностью.

    А компаратору все же придется задать порог чувствительности.
    Исходная-то задача была про сравнение.

    К>>>>
  • цифровые фильтры

    S>>> А вот это, конечно, дело темное Но, опять же, нафига в них сравнивать числа, отбрасывая младшие разряды? Разве что для скорости...


    К>>Это не просто отбрасывание. Это сглаживание.


    S> Можно поподробнее? Что и как тут сглаживается (чем отбрасывание лучше сглаживания, если не принимать в расчет быстродействие)?


    Все тот же шум квантования...
  • Перекуём баги на фичи!
    Re[11]: Сравнение float
    От: Sergey Россия  
    Дата: 26.02.02 13:25
    Оценка:
    Здравствуйте Кодт, Вы писали:

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


    К>>>Банковское округление — это, грубо говоря, 0.04 --> 0.0, 0.05 --> 0.1,

    К>>>т.е. ошибка составляет 0.05 вместо 0.10. Тем не менее, она накапливается.

    S>> Не, не так прямолинейно. "Банковское округление" — это, например (есть, вроде бы, несколько способов) когда 1.05 -> 1.1,

    S>>а 2.05 -> 2.0. Если сумма цифр четная и последняя цифра — пятерка, округляем в одну сторону, нечетная — в другую. Ошибка не накапливается, если числа можно считать случайными.

    К>А если не случайными?


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

    К>>>>>
  • снятие показаний с аналоговых устройств

    S>>>> Ну и зачем тут может понадобиться отбрасывать значения младших разрядов?


    К>>>Например, соотношение сигнал/шум составляет 1:0.01.

    К>>>Какой тогда смысл снимать с АЦП больше 2 разрядов?

    S>> IMHO (потому что лень считать), если ограничиться двумя разрядами, соотношение сигнал/шум будет хуже. Сложится (среднеквадратично) шум квантования и помеха.


    К>Да, насчет шума квантования — недодумал.

    К>Вычисления — пожалуйста, с большой точностью.

    К>А компаратору все же придется задать порог чувствительности.

    К>Исходная-то задача была про сравнение.

    Ну, компаратору придется как минимум приделать гистерезис, после чего сравнивать придется не на равенство/неравенство, а на больше/меньше (почти что "обычное" сравнение с округлением).

    К>>>>>
  • цифровые фильтры

    S>>>> А вот это, конечно, дело темное Но, опять же, нафига в них сравнивать числа, отбрасывая младшие разряды? Разве что для скорости...


    К>>>Это не просто отбрасывание. Это сглаживание.


    S>> Можно поподробнее? Что и как тут сглаживается (чем отбрасывание лучше сглаживания здесь должно было быть написано "округления", если не принимать в расчет быстродействие)?


    К>Все тот же шум квантования...


    Ну так он при отбрасывании разрядов просто увеличится. А вообще, по крайней мере в КИХ-фильтрах, IMHO, сравнивать ничего не требуется. Знай себе умножай да складывай...
  • Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
    Re: Сравнение float
    От: artgonch  
    Дата: 01.09.04 14:58
    Оценка:
    Здравствуйте!
    Извините, что снова поднимаю эту тему. Есть такой код:

        const float delta = 0.001f;
        for (int i = 0; i < GetCount(); )
        {
            GetRecord(i);
            //if (m_f1 < f)
            if (fabs(m_f1 - f) < delta)
                DeleteRecord(i);
            else
                i++;
        }

    Использую VS.NET 2002. Фугкция DeleteRecord() не вызыввется даже когда разность меньше погрешности. В чем может быть причина?
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.