简体   繁体   中英

Floating point: how many matching significant figures?

In C, Given two single or double precision floating point numbers, is there an easy way to determine how many of their significant figures "match"? Ie if I have two such numbers with decimal representation 1.64298272 and 1.64298296 I would like to obtain the result 7 . If I was concerned with decimal places this would be easy but I'm not sure how to go about it if I'm interested in significant figures.

To do an exact compare, the value must be converted with sufficient precision. DBL_DECIMAL_DIG (typical 17) is enough for double to make unique strings as suggested by @ryyker

Form a string for both values

//         -   d   .    digits - 1        e   -  expo \0
#define N (1 + 1 + 1  + DBL_DECIMAL_DIG + 1 + 1 + 5 + 1)
char buf[N + 10];  // Some extra too to cope with strange NaN payloads
// Consider changing round mode to "round towards 0.0.  See below notes.
snprintf(buf, sizeof buf,"%+.*e", DBL_DECIMAL_DIG - 1, value);

After testing for same sign and exponent, walk leading digits.

Some sample hacked code.

if (buf1[0] != buf2[0]) return 0; // sign test
e1 = strchr(buf1, 'e');
e2 = strchr(buf1, 'e');
if (strcmp(e1,e2)) return 0; // expo test (non-finite concerns omitted here for brevity)
digit = 0;
s1 = buf1;
s2 = buf2;
while (s1 < e1 && s2 < e2) {
  if (isdigit(*s1)) {
    if (*s1 == *s1) digit++;
    else break;
  }
  s1++; s2++;
}
return digit;

If code attempts to do this without s*printf() , the math involved to examine a binary based floating-point number and convert to decimal for compare will effectively re-do what sprintf() does already.


Limitations:

This answers is at best a start. Consider foo(0.0, 0.0) and foo(DBL_TRUE_MIN, DBL_TRUE_MIN) here would return DBL_DECIMAL_DIG . As DBL_TRUE_MIN is about 4.940656...e-324 yet as an exact decimal has about 751 significant digits, should 751 be returned?

Research is needed also to consider edge cases .

See @Eric Postpischil good idea about first changing the rounding mode. IAC, using sprintf() is limited by a quality of implementation.


[Update]

If a C library implements FP perIEEE-754 , then to well handle many cases, a +3 to the precision is recommended.

char buf[N + 3 + 10];
// Consider changing round mode to "round towards 0.0.  See below notes.
snprintf(buf, sizeof buf,"%+.*e", DBL_DECIMAL_DIG + 3 - 1, value);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM