1) вы пытаетесь сделать равные сравнения с плавающей точкой. Некоторые форматы с плавающей запятой, которые будут работать, но форматы IEEE не будут работать. Вы не можете делать сравнений сравнений. Вам нужно преобразовать этот float в int, а затем сравнить int. С целыми числами (не ограничивая себя до 32 бит или что-то еще здесь) есть только один способ представить каждый номер, чтобы вы могли делать равные сравнения.
2) помните, что математика с плавающей запятой является базой 2, и вы просите сделать базу 10 вещей. поэтому будут проблемы с конверсией, усечение. Кроме того, я снова предполагаю, что вы используете IEEE, что означает, что у вас есть три режима округления (база 2), поэтому вам также придется иметь дело с этим. Вы захотите сделать что-то вроде double_to_integer ((double * 1000.0) +0.5) и сравнить их. Я не удивлюсь, если вы найдете угловые случаи, которые не работают.
Более интересная информация по этой проблеме. Следует отметить, что использование союзов таким образом, не поддерживается стандартом C, но часто просто бывает на работу ...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
double trunc(double d)
{
return (d>0) ? floor(d) : ceil(d) ;
}
int comparedigits(float a , float b)
{
if (trunc(1000.0 * a) == trunc(1000.0 * b))
{
return 1;
}
return 0;
}
union
{
unsigned int ul;
float f;
} fun;
union
{
unsigned int ul[2];
double d;
} dun;
int main (void)
{
float g;
float h;
int t;
g = 2.346;
h = 2.34599;
t = comparedigits(g,h);
printf("%u\n",t);
printf("raw\n");
fun.f=g; printf("0x%08X\n",fun.ul);
fun.f=h; printf("0x%08X\n",fun.ul);
dun.d=g; printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
dun.d=h; printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
printf("trunc\n");
dun.d=trunc(1000.0 * g); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
dun.d=trunc(1000.0 * h); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
printf("trunc\n");
dun.d=trunc(1000.0F * g); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
dun.d=trunc(1000.0F * h); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
printf("floor\n");
dun.d=floor(1000.0 * g); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
dun.d=floor(1000.0 * h); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
printf("ceil\n");
dun.d=ceil(1000.0 * g); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
dun.d=ceil(1000.0 * h); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
printf("%u\n",(unsigned int)(g*1000.0));
printf("%u\n",(unsigned int)(h*1000.0));
if (trunc(1000.0F * g) == trunc(1000.0F * h))
{
printf("true\n");
}
else
{
printf("false\n");
}
return(0);
}
компиляции и запуска
gcc test.c -o test -lm
./test
1
raw
0x401624DD
0x401624B3
0x4002C49B_A0000000
0x4002C496_60000000
trunc
0x40A25200_00000000
0x40A25200_00000000
trunc
0x40A25400_00000000
0x40A25200_00000000
floor
0x40A25200_00000000
0x40A25200_00000000
ceil
0x40A25400_00000000
0x40A25400_00000000
2345
2345
false
Так делает 1000 * х в одиночном математика вместо двойной математики, как представляется, устраняет проблему
1000,0 * a - смешанный режим. 1000.0 является двойным по стандарту C, если не указано, что он один. И a является одиночным, поэтому a преобразуется в double, математика выполняется как двойная, а затем подается на двойную функцию. 1000.0F является одиночным, a является одиночным, поэтому умножение выполняется как единая математика, затем оно преобразуется в double. Поэтому, возможно, настоящая проблема заключается в преобразовании и округлении g и h в double. Нужно будет больше копать в различиях мантиссы ...
Я думаю, что ключ в этом, двойной раз один 1000.0 * x результаты
trunc
0x40A25200_00000000
0x40A25200_00000000
Если они равны, то все, что вы делаете, будет одинаковым. Когда это один раз один, а затем преобразованный в двойной, они различаются.
trunc
0x40A25400_00000000
0x40A25200_00000000
и это заставляет работать ваш код (для этих двух конкретных значений).
false
Вы понимаете, что когда вы думаете, что у вас может быть ровно 2,567, у вас может быть 2.56699999 ...? – hvd
[Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой] (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) –
Извините, исправлено - 3 десятичных знака – MistyD