-2

I'll cut right to the chase: I am trying to parse a string with strtold to get a long double, but it is giving me the wrong value. Specifically, I am parsing the number 97777777777777777777777777777777777777.0, but strtold parses it as 97777777777777777779155292002375958528.000000. I check errno, HUGE_VALL, and end_ptr, but errno does not report an error, my number is no where near HUGE_VALL, and end_ptr is empty. I've been trying to debug this for a while, but I'm at my wits end. I don't think this is a bug in strtold because the same problem happens if I take out some 7's from the number. This code works for small numbers, like 97. I would greatly appreciate it if someone could help me here.

The code:

#include <stdio.h>          // printf
#include <stdlib.h>         // strtold
#include <errno.h>          // errno
#include <string.h>         // strerror
#include <math.h>           // HUGE_VALL

int main(int argc, char** argv)
{
    char* theNum = "97777777777777777777777777777777777777.0";
    printf("HUGE_VALL = %Lf\n", HUGE_VALL);    // just to make sure I'm not insane
    char* endbuf;
    errno = 0;
    long double n = strtold(theNum, &endbuf);
    if (n == HUGE_VALL && errno != 0)
    { printf("strtold err: %s\n", strerror(errno)); }
    else
    { printf("strtold status: %s\n", strerror(errno)); }
    printf("the number: %Lf\n", n);
    printf("endbuf: %s\n", endbuf);
    return 0;
}

Output:

HUGE_VALL = inf
strtold status: Success
the number: 9777777777777777777835998445568.000000
endbuf: 

Some details:

64-bit Red Hat Linux: (uname -i says x86_64)

Running Red Hat Enterprise Linux Server release 7.1 (Maipo)

gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9)

I'm compiling using c99: c99 primefactors_test.c ../../src/primefactors.c -o primefactors_test -I../../include/ -O3 -lm

I also tried a simpler compile statement where I take out all of the unneeded dependencies: c99 primefactors_test.c -o primefactors_test -lm

Sharif
  • 481
  • 1
  • 4
  • 10
  • @vishal fixing that now, will let you know if it fixes anything – Sharif Oct 12 '15 at 08:34
  • @vishal I used %Lf instead, problem still exists – Sharif Oct 12 '15 at 08:37
  • 1
    `long double` don't have such large precision. If `long double` on your system is 80-bit Intel extended precision then it has only 64 bits of mantissa and can store up to ~19.2 decimal degits. If it's 64-bit double precision IEEE-754 like the case of MSVC then it can only be precise to ~15.95 digits – phuclv Oct 12 '15 at 08:41
  • @Lưu Vĩnh Phúc, in float.h, it says that double and long double are guaranteed to be able to represent up to 1E+37. Am I reading that correctly? – Sharif Oct 12 '15 at 08:47
  • @user2649759 you're misreading the **precision** and **range**. `LDBL_MAX` represents the range of values that the type can store, but not all values inside that range can be stored. No floating-point type has infinite precision. In this case it's limited to 64 bits. Read how floating-point values are stored first – phuclv Oct 12 '15 at 08:49
  • @user2649759: but are you *understanding* it? Do you sincerely believe you can store 10,000,000,000,0...000 (22 zeroes omitted) different **significant digits** on your computer? On the entire Internet? On every sand grain on Earth? – Jongware Oct 12 '15 at 08:49
  • Ah, I see. Thanks for clearing that up. – Sharif Oct 12 '15 at 08:49
  • @Jongware, I suppose not with a floating point number. I guess I got carried away :) – Sharif Oct 12 '15 at 08:51
  • @user2649759: do read the various answers to http://stackoverflow.com/q/56947/2564301, it will help you in understanding the basics. – Jongware Oct 12 '15 at 08:53
  • @Jongware thanks. I actually did learn about the technicalities of floating point numbers in a college course, but have not had to deal with them until now. It's always different when you learn something and actually apply it. – Sharif Oct 12 '15 at 08:56
  • Note that `if (n == HUGE_VALL && errno != 0)` is not a good test. I am pretty sure you meant to use `||` instead of `&&`. Also, `==` with floating points is a tricky one. – Alexis Wilke Dec 10 '22 at 19:24

1 Answers1

0

Apart from checking the range of a data type (HUGE_VALL or may be LDBL_MAX) verify also its precision, that is how many decimal digits of the value can be reliably represented by the type. (added) The information may be available by the LDBL_DIG macro, possibly defined in <float.h>.

See the Caladan's answer to the question long double (GCC specific) and __float128

Suppose this one may be helpful, too: Implementation of type "long double" with GCC and C++11

Community
  • 1
  • 1
CiaPan
  • 9,381
  • 2
  • 21
  • 35
  • Cool, how do I check the precision? – Sharif Oct 12 '15 at 08:38
  • In C++ use [`std::numeric_limits::digits10`](http://en.cppreference.com/w/cpp/types/numeric_limits/digits10) ([What is the meaning of numeric_limits::digits10](http://stackoverflow.com/q/747470/995714)). I don't know how to do it in C. To know the number of bits in the mantissa use `std::numeric_limits::digits` – phuclv Oct 12 '15 at 08:52
  • @user2649759 See '(added)' in my answer. – CiaPan Oct 12 '15 at 09:51