0

I'm trying to add together 1 and 0.0000000000000000000000000000000000000117549435... (2**-126), but for some reason I get number 1 printed. I'm new to C and I'm guessing it has something to do with IEEE754? I've tried using doubles and long doubles but i haven´t got the result i need. Not sure if it changes anything, but i need 150 decimal digits.

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
int main() {
    float num;
    float example;
    num = 1;
    example = 1*pow(2, -126);
    num = num + example
    printf("%.150f", num);
    return 0;
}
rosewaldo
  • 11
  • 2
  • 1
    `150 decimal digits` is not gonna achievable with any of the default floating-point types in C in any of the current implementations – phuclv Apr 08 '20 at 05:14
  • 1
    Does this answer your question? [Store and work with Big numbers in C](https://stackoverflow.com/questions/2640625/store-and-work-with-big-numbers-in-c) – phuclv Apr 08 '20 at 05:15
  • Not quiet? that one is int not float, unless i'm not seeing what you want me to see – rosewaldo Apr 08 '20 at 05:20
  • 3
    If you need 150 digits, you're going to have to use an arbitrary-precision floating point library. Even the biggest IEE 754 types don't get close to 150 decimal digits. A `float` (`binary32`) can represent 6-7 decimal digits; a `double` (`binary64`) about 16-17 digits. If you have `binary128` (might be `long double`), then you get about 34 decimal digits; if you have `binary256`, you get about 74 decimal digits (per Wikipedia on [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754)). You'd need the non-standardized (non-existent) `binary512` to get close to 150 decimal digits. – Jonathan Leffler Apr 08 '20 at 05:23
  • 1
    The point is that you must use a [tag:bignum] library. Did you check the famous GMP library mentioned in the other answer? *"GMP is a free library for arbitrary precision arithmetic, operating on signed integers, rational numbers, and **floating-point numbers**"*. Of course there are many other well-known libraries like Boost.Multiprecision. There are lots of duplicates already on SO – phuclv Apr 08 '20 at 05:23
  • 1
    Are the values you are going to use going to be always "1+small"? You could program specifically for that, while staying with the standard types. – Yunnosch Apr 08 '20 at 05:24
  • Are you sure you really need 150 significant digits, or do you just need an exponent range ±126? Using floating-point numbers with that many digits implies staggering precision. Using integers with that many digits implies cryptographic calculations — or, at least, that's probably the most common reason. Blockchain etc counts as 'cryptographic' for this purpose. – Jonathan Leffler Apr 08 '20 at 05:39
  • Yeah, you should really explain what you actually need. Is it a huge amount of significant digits, or do you just need to deal with very small numbers? – klutt Apr 08 '20 at 06:18

1 Answers1

3

Floating point format can't store every number.

The numbers that it can store goes in steps. Like

 1.00000000000000000000000
 1.00000011920928955078125
 1.00000023841857910156250
 1.00000035762786865234375
 ...

So the number you are trying to store, i.e.

 1.0000000000000000000000000000000000000117549435..

can't be represented in float format. So in your case it's rounded to 1.0

Try this program:

#include <stdio.h>
#include <assert.h>

union
{
    float f;
    unsigned u;
} val;

int main() {
    assert(sizeof(float) == 4);
    assert(sizeof(unsigned) == 4);
    val.u = 0x3f800000;
    printf("0x%08x -> %.50f\n", val.u, val.f);
    ++val.u;
    printf("0x%08x -> %.50f\n", val.u, val.f);
    ++val.u;
    printf("0x%08x -> %.50f\n", val.u, val.f);
    ++val.u;
    printf("0x%08x -> %.50f\n", val.u, val.f);
    return 0;
}

Output:

0x3f800000 -> 1.00000000000000000000000000000000000000000000000000
0x3f800001 -> 1.00000011920928955078125000000000000000000000000000
0x3f800002 -> 1.00000023841857910156250000000000000000000000000000
0x3f800003 -> 1.00000035762786865234375000000000000000000000000000

The above code uses a union of float and unsigned and an increment of the unsigned to get the next float.

Another way is to use nextafterf function to get the next representable float. Like:

#include <stdio.h>
#include <assert.h>
#include <math.h>

union
{
    float f;
    unsigned u;
} val;

int main() {
    assert(sizeof(float) == 4);
    assert(sizeof(unsigned) == 4);
    val.f = 1*pow(2, -126);
    printf("0x%08x --> %.200f\n", val.u, val.f);
    val.f = nextafterf(val.f, 1.0);
    printf("0x%08x --> %.200f\n", val.u, val.f);
    val.f = nextafterf(val.f, 1.0);
    printf("0x%08x --> %.200f\n", val.u, val.f);
    val.f = nextafterf(val.f, 1.0);
    printf("0x%08x --> %.200f\n", val.u, val.f);
    return 0;
}

Output:

0x00800000 --> 0.00000000000000000000000000000000000001175494350822287507968736537222245677818665556772087521508751706278417259454727172851562500000000000000000000000000000000000000000000000000000000000000000000000000
0x00800001 --> 0.00000000000000000000000000000000000001175494490952133940450443629595204006810278684798281709160328881985245648433835441437622648663818836212158203125000000000000000000000000000000000000000000000000000
0x00800002 --> 0.00000000000000000000000000000000000001175494631081980372932150721968162335801891812824475896811906057692074037412943710023682797327637672424316406250000000000000000000000000000000000000000000000000000
0x00800003 --> 0.00000000000000000000000000000000000001175494771211826805413857814341120664793504940850670084463483233398902426392051978609742945991456508636474609375000000000000000000000000000000000000000000000000000
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • How would one get said steps? Like if I input a certain float how to get the next step? – rosewaldo Apr 08 '20 at 05:13
  • The union trick was actually a remarkable good way of illustrating this, but you should add a short explanation on what it is and why it works and link something that explains unions in more detail. – klutt Apr 08 '20 at 05:14
  • 1
    @rosewaldo There is the nextafterf function. Answer updated – Support Ukraine Apr 08 '20 at 05:33