LINUX.ORG.RU

C, double compare function


0

0

Всем доброй ночи. Ребят, подскажите, пожалуйста, в каких случаях моя реализация функции сравнения будет работать некорректно(в реальном использовании сравниваться будут double'ы с точностью до 8-10 знака)

bool compare_doubles(const double const* one, const double const* two, unsigned int float_points)
{
	assert(one != NULL);
	assert(two != NULL);
	assert(float_points > 0);

	unsigned int multiplexor = 1;
	for (unsigned int index = 0; index < float_points; ++index)
		multiplexor *= 10;

	return ((int)((*one - *two) * multiplexor)) == 0;
}

Я читал мнения и разработки других людей. К примеру обсуждение тут: http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-dou... , но не могу найти нужную реализацию :(

10 знаков int'ом не получите - используйте long или long long. Да, а чем вам не нравится конструкция

fabs(one - two) < x;
где x, скажем, 1e(-10)?

Eddy_Em ☆☆☆☆☆
()

Не осилил что это за хрень, но double обычно сравнивают так

if (fabs(a - b) < 1e-10) ....

Reset ★★★★★
()

o.O

я глупец, но я бы делал так:

#include <limits.h>
#include <math.h>
int compare_doubles(const void *a,const void * b) {
   double _a=*((double *)a);
   double _b=*((double *)b);
   double _c=_a-_b;
   if ( (fabs(_c) < DBL_EPSILON) ) {
     return 0;
   } else if ( _c > 0 ) return 1;
   return -1;
}
int equals_double(const void *a,const void *b) {
   return fabs(*(double *)a - *(double *)b) < DBL_EPSILON 
}
qnikst ★★★★★
()

вроде самое простое и одновременно вменяемое:

#include <cmath>
#include <limits>

bool AreSame(double a, double b) {
    return fabs(a - b) < std::numeric_limits<double>::epsilon();
}
shty ★★★★★
()

Спасибо

Спасибо за ответы. Буду тестировать следующую реализацию:

#include <float.h>
#include <math.h>
bool compare_doubles(const double const* one, const double const* two)
{
   assert(one != NULL); 
   assert(two != NULL);

   return fabs(*one - *two) < DBL_EPSILON;
}

andreyse
() автор топика
Ответ на: комментарий от Reset

Указатели удобнее для меня в виду решаемой задачи(массив входных значений)

andreyse
() автор топика
Ответ на: Спасибо от andreyse

+1 к Reset. (только он ещё слова умные знает)

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

ИМХО же лучше использовать int compar(), -1 a<b, 0 a==b, 1 a>b, что если нужно сравнение, то сразу эту функцию использовать.

qnikst ★★★★★
()
Ответ на: Спасибо от andreyse

Можно еще вопросик: что за тип такой «bool» - [un]signed char, [un]signed short или [un]signed int? Вы его как определяете?

Eddy_Em ☆☆☆☆☆
()
Ответ на: Спасибо от andreyse

Такое работать не будет , как пример 1e-32 и 1e-30

Читай что такое DBL_EPSILON (реализация libc не отличает 1. и 1.+ DBL_EPSILON)

Т.е. если есть value и correct_value != 0 то сравнение будет

fabs(value - correct_value) < TOLERANCE * fabs(correct_value)

Если же correct_value == 0, то надо обрабатывать по особому (в зависимости от применения). В моем быдло-коде используются такие конструкции

fabs(value - correct_value) < TOLERANCE * fabs(correct_value + ((double) correct_value < TOLERANCE) )
fabs(value - correct_value) < TOLERANCE * fabs(correct_value + ((double) correct_value == 0.) )

ogronom
()
Ответ на: комментарий от qnikst

Если я правильно понял топик стартера, то нужно не точное сравнение, а сравнение с погрешностью (~ 1e-10). Т.е. твой compar работать не будет

ogronom
()
Ответ на: комментарий от ogronom

Что-то совсем уже не соображаю, когда correct_value == 0. (т.е. опять же fabs(correct_value) < TOLERANCE_ZERO )

надо заменять относительную ошибку на абсолютную

ogronom
()
Ответ на: комментарий от ogronom

будет (если про этот говорить http://www.linux.org.ru/jump-message.jsp?msgid=4868287&cid=4868335) хотя может нужно изменить константу с DBL_EPSILON на более большую.

Читай что такое DBL_EPSILON (реализация libc не отличает 1. и 1.+ DBL_EPSILON)

да, только реализация libc тут нипричём.

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

Ссылка не открывается, но если это о примерах выше, то все же работать не будет.

Вот контр примеры

Два числа (1e8+1) и 1e8. Разница между ними = 1 > DBL_EPSILON. Тем не менее эти два числа равны с точностью 8 знаков.

Или тоже самое 1e-30 и 1e-20. Разница между ними < DBL_EPSILON, а числа отличаются на 10 порядков

ogronom
()
Ответ на: комментарий от ogronom

> Два числа (1e8+1) и 1e8. Разница между ними = 1 > DBL_EPSILON. Тем не менее эти два числа равны с точностью 8 знаков.

Или тоже самое 1e-30 и 1e-20. Разница между ними < DBL_EPSILON, а числа отличаются на 10 порядков

это правильное поведение с точки зрения задачи ТС. (в реальном использовании сравниваться будут double'ы с точностью до 8-10 знака)

хотя в целом да, ты прав.

fabs(value - correct_value) < TOLERANCE * fabs(correct_value)

qnikst ★★★★★
()
Ответ на: комментарий от Eddy_Em

> stdbool.h - для C++. В сях типа bool нет.

«The header stdbool.h in the C Standard Library for the C programming language contains four macros. This header was introduced in C99.»

lester ★★★★
()
Ответ на: комментарий от lester

У меня такого нет:

locate stdbool.h
/usr/include/c++/4.4.1/tr1/stdbool.h
/usr/lib/gcc/i586-manbo-linux-gnu/4.4.1/include/stdbool.h
/usr/share/sdcc/include/stdbool.h
Да и не вижу смысла. Я обычно в качестве булевых переменных использую unsigned char.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

> stdbool.h - для C++. В сях типа bool нет.

Все-таки хотя бы одну книжечку по языку Си стоит прочитать.

anonymous
()
Ответ на: комментарий от Eddy_Em

> Да и не вижу смысла.

Смысл то как раз и есть.

Я обычно в качестве булевых переменных использую unsigned char.

Нормальная практика использовать int.

anonymous
()
Ответ на: комментарий от Reset

Точно, и даже подключается. Тип bool занимает один байт и принимает только значения 1 и 0. Спасибо, буду знать - вдруг где понадобится.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

> Тип bool занимает один байт

В общем случае неправильное утверждение.

Спасибо, буду знать - вдруг где понадобится.

Совсем не давно было «не вижу смысла», а теперь «вдруг где понадобится»...

anonymous
()
Ответ на: комментарий от anonymous

Тип bool занимает один байт

В общем случае неправильное утверждение.

Это я по sizeof'у посмотрел.

Совсем не давно было «не вижу смысла», а теперь «вдруг где понадобится»...

Так этот bool, оказывается, автоматически принимает значения только 0 или 1. Может быть полезным в некоторых случаях.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

> Так этот bool, оказывается, автоматически принимает значения только 0 или 1. Может быть полезным в некоторых случаях.

bool, как и везде в подобных языках, принимает значение 0 как false и true как все остальные возможные значения типа.

anonymous
()

> const double const* one

o_O

const double *const one

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.