1

How to by a given value like 0.00...001 find the position of 1?

I have a sample code like this:

constexpr int PrecisionFromDouble(double val)
{
    int d = 1.0 / val;
    int log = 0;

    while (true)
    {
        d = d / 10;
        if (d == 0)
            break;
        ++log;
    }
    return log;
}

It works with the following values:

static_assert(PrecisionFromDouble(0.0001) == 4);
static_assert(PrecisionFromDouble(0.001) == 3);
static_assert(PrecisionFromDouble(0.01) == 2);
static_assert(PrecisionFromDouble(0.1) == 1);
static_assert(PrecisionFromDouble(1.0) == 0);

but does not work with 0.00001, because d becomes 9999.

EDIT1:

It works a bit better with std::round in the first line of the function:

    int d = static_cast<int>(std::round(1.0 / val));

this should work with the most double literals like 0.00..001

AbdelAziz AbdelLatef
  • 3,650
  • 6
  • 24
  • 52
Dmitriano
  • 1,878
  • 13
  • 29
  • 6
    Make sure to read [this](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) if you haven't already. – cigien Sep 22 '20 at 22:47
  • 2
    Output to a string, look for the first 1 in the string. Figure out the magnitude from there. – Eljay Sep 22 '20 at 22:50
  • @cigien At least I understand that it is something related to the power of two :) – Dmitriano Sep 22 '20 at 22:51
  • 4
    @Dmitriano Not all decimal fractions can be represented as exact eqivalent binary fractions. Hence you can't do that. – πάντα ῥεῖ Sep 22 '20 at 22:51
  • @πάνταῥεῖ Why not? If a double value like 0.00..001 does not exist, its literal exists, for example :) or `std::stod("0.00...001")` exists. – Dmitriano Sep 22 '20 at 23:37
  • 3
    @Dmitriano `its literal exists` Yes, but your input variable is a `double` not a `string`. Once you assign the value to a double, it has no memory of the string you entered, or whether the assignment was originally made from `stod("0.00...001000..")` vs. `stod("0.00...000999..")`. – dxiv Sep 22 '20 at 23:45

3 Answers3

1
main(){ 
    int error;
    float fvalue=0.0001;
    char *cstr = ftoa(dvalue,&error);
    string str(cstr);
    size_t position = str.find_first_of("1",0);
    cout << position <<endl;
}
  • I think you need to subtract `1` from `position` if the value of `dvalue` is less than `1`, because of the presence of the period `.` – AbdelAziz AbdelLatef Sep 22 '20 at 23:53
  • you may be right, but i dont know what the guy means with position. if is position after dot, i should subtract 2. mostly depends how the float is rappresented after conversion. anyway your solution is very clever. –  Sep 23 '20 at 00:15
  • You can look at his examples. – AbdelAziz AbdelLatef Sep 23 '20 at 00:19
  • beware, this may not work if `0.000...1` is converted to `0.000...999...`. Besides `ftoa` isn't standard. You need to print in much larger precision using `sprintf` and find the first non-zero digit – phuclv Sep 23 '20 at 01:42
1

I think you can use log10

#include <math.h>
constexpr int PrecisionFromDouble(double val)
{
    return -(int)log10(val);
}
AbdelAziz AbdelLatef
  • 3,650
  • 6
  • 24
  • 52
0

This one works (corrected after phuclv's comment):

constexpr int PrecisionFromDouble(double val)
{
  int log = 0;
  unsigned long long m(10);

  while (1. / m >= val)
    log++, m*= 10;

  return log;
}
Vlad Feinstein
  • 10,960
  • 1
  • 12
  • 27
  • 2
    no it doesn't quite work https://gcc.godbolt.org/z/c3f5dE repeating multiplication makes the error larger after each cycle so it's not a solution – phuclv Sep 22 '20 at 23:17
  • 1
    @phuclv Ouch! I only went to `8` in my test... Well, we don't know how far Dmitriano needs to go :) – Vlad Feinstein Sep 22 '20 at 23:21
  • @VladFeinstein I need more than 8 – Dmitriano Sep 22 '20 at 23:27
  • @phuclv - it appears that the issue was with internal representation of `1e-11` : `val 9.9999999999999994e-12 double` – Vlad Feinstein Sep 22 '20 at 23:50
  • no it still just works for a small range of values https://gcc.godbolt.org/z/T755xo you must avoid a loop if you really want to do it that way, and avoid integer types which will overflow once the value becomes small enough – phuclv Sep 23 '20 at 01:25