0

Given a harmonic series 1 - 1/2 + 1/3 - 1/4... = ln(2), is it possible to get a value of 0.69314718056 using only float values and using only basic operations (+,-,*,/). Are there any algorithms which can increase the precision of this calculation without going to unreasonably high values of n (current reasonable limit is 1e^10)

What I currently have: this nets me 8 correct digits -> 0.6931471825

EDIT The goal is to compute the most precise summation value using only float datatypes

int main()
{
    float sum = 0;
    int n = 1e9;
    double ans = log(2);
    int i;
    float r = 0;

    for (i = n; i > 0; i--) {
        r = i - (2*(i/2));
        if(r == 0){
            sum -= 1.0000000 / i;
        }else{
            sum += 1.0000000 / i; 
        }
    }

    printf("\n%.10f", sum);
    printf("\n%.10f", ans);
    return 0;
}
Isaac S.
  • 1
  • 1
  • 1
    You will not likely be able to change the precision of `float`. Can't you use `long double` instead? – Ted Lyngmo Jan 30 '23 at 21:48
  • 2
    `float sum = 0;`? `FLT_DIG` is normally 6. It's a bit hard to get 11 digits out of one of those. – Andrew Henle Jan 30 '23 at 21:51
  • 4
    You can't for a simple reason (among the others) that `0.69314718056` is not representable as `float` – Eugene Sh. Jan 30 '23 at 21:51
  • This sum of this series up to and including 10^10 is .6931471805549… (courtesy of Wolfram Alpha), which rounds to .69314718055, so, even if you compute with infinite precision, you cannot get .69314718056 from 10^10 terms. (I suppose you could get .69314718056 by computing with some limited precision such that the rounding errors produce that.) – Eric Postpischil Jan 30 '23 at 21:56
  • What you currently have — 0.6931471825 — looks perfectly fine to me. I'd say you've achieved your goal. That's the best approximation to ln(2) that it's possible to get using a `float`. – Steve Summit Jan 30 '23 at 22:45
  • 1
    You can take a look at Kahan summation: https://en.wikipedia.org/wiki/Kahan_summation_algorithm. But you'd also need to compute the fractions with more precision and probably need more terms. – chtz Jan 31 '23 at 09:09
  • You can do this by nesting more floats together see [edit1 integration precision](https://stackoverflow.com/a/28020934/2521214) its simple example of doing this... if you use power of 10 as threshold you can simply print the numbers in nested way too so no need for any bignum lib... – Spektre Feb 01 '23 at 06:10

2 Answers2

5

On systems where a float is a single-precision IEEE floating point number, it has 24 bits of precision, which is roughly 7 or (log10(224)) digits of decimal precision.

If you change

double ans = log(2);

to

float ans = log(2);

You'll see you already get the best answer possible.

0.6931471 82464599609375       From log(2), casted to float
0.6931471 82464599609375       From your algorithm
0.6931471 8055994530941723...  Actual value
  \_____/
  7 digits

In fact, if you use %A instead of %f, you'll see you get the same answer to the bit.

0X1.62E43P-1  // From log(2), casted to float
0X1.62E43P-1  // From your algorithm
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
ikegami
  • 367,544
  • 15
  • 269
  • 518
2

@ikegami already showed this answer in decimal and hex, but to make it even more clear, here are the numbers in binary.

ln(2) is actually:

0.1011000101110010000101111111011111010001110011111…

Rounded to 24 bits, that is:

0.101100010111001000011000

Converted back to decimal, that is:

0.693147182464599609375

...which is the number you got. You simply can't do any better than that, in the 24 bits of precision you've got available in a single-precision float.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103