상수 머신 엡실론값?

unuseid의 이미지

아래는 실수를 문자열로 변환해주는 함수 인데 허점이 있는거 같습니다.

잘 작동할도 있고 오작동할때도 있는데
오작동 하면
30.8을 변환하면 30.7999999 가 되버립니다.

원인을 파악하기 위해 로그를 남기던중
do while부분에서 문제가 발생하기 시작하는것을 발견했습니다.

상수인 FLT_EPSILON값이 정상작동할때는 0.00000으로 출력되고
오작동시에는 nan으로 출력되며 do while문을 과도하게 많이 돌게 됩니다.

왜 이런현상이 나타나며 해결방법은 무었일까요?

size_t utils_floatToText(double data,
                         uint8_t * string,
                         size_t length)
{
    size_t intLength;
    size_t decLength;
    int64_t intPart;
    double decPart;
 
    if (data <= (double)INT64_MIN || data >= (double)INT64_MAX) return 0;
 
    intPart = (int64_t)data;
    decPart = data - intPart;
    if (decPart < 0)
    {
        decPart = 1 - decPart;
    }
    else
    {
        decPart = 1 + decPart;
    }
 
    if (decPart <= 1 + FLT_EPSILON)
    {
        decPart = 0;
    }
 
    if (intPart == 0 && data < 0)
    {
        // deal with numbers between -1 and 0
        if (length < 4) return 0;   // "-0.n"
        string[0] = '-';
        string[1] = '0';
        intLength = 2;
    }
    else
    {
        intLength = utils_intToText(intPart, string, length);
        if (intLength == 0) return 0;
    }
    decLength = 0;
    if (decPart >= FLT_EPSILON)
    {
        int i;
        double noiseFloor;
 
        if (intLength >= length - 1) return 0;
 
        i = 0;
        noiseFloor = FLT_EPSILON;
        do
        {
            decPart *= 10;
            noiseFloor *= 10;
            fprintf(stderr,"decPart = %f , noiseFloor = %f \n",decPart,string + intLength);
            i++;
        } while (decPart - (int64_t)decPart > noiseFloor);
 
        decLength = utils_intToText(decPart, string + intLength, length - intLength);
        if (decLength <= 1) return 0;
 
        // replace the leading 1 with a dot
        string[intLength] = '.';
    }
    fprintf(stderr,"decPart = %f , convert = %s \n",decPart,string + intLength);
    return intLength + decLength;
}

아래는 실행 로그 입니다.

dataP->value.asFloat : 31.500000
dataP->type : 7
lwm2m_data_serialize
floatttttttttt
decPart = 15.000000 , noiseFloor = 0.000000 <--- 정상작동시의 do while 문
decPart = 15.000000 , convert = .5�r
utils_float64ToPlainText 31.500000 31.5%
report change!
expernet data
report change!
dataP->value.asFloat : 31.700000
dataP->type : 7
lwm2m_data_serialize
floatttttttttt
decPart = 17.000000 , noiseFloor = nan <--------정상작동시 0.00000으로 출력되던 상수가 nan으로 출력되며 do while문을 과도하게 많이 돌며 오작동
decPart = 170.000000 , noiseFloor = nan
decPart = 1700.000000 , noiseFloor = nan
decPart = 17000.000000 , noiseFloor = nan
decPart = 170000.000000 , noiseFloor = nan
decPart = 1700000.000000 , noiseFloor = nan
decPart = 17000000.000000 , noiseFloor = nan
decPart = 17000000.000000 , convert = .6999999
utils_float64ToPlainText 31.700000 31.6999999 �