4

I would like to write a function which finds the shortest decimal between value and the nearest two floating point values which are larger and smaller respectively.

For example the decimal number 0.1 has

decimal representation: 0.1
binary representation: 0 01111011 10011001100110011001101
actual value of binary representation: 0.10000000149011612

The next smaller float value can be obtained by switching the last 1 of the binary representation to a zero:

binary: 00111101110011001100110011001100
value: 0.09999999403953552

The next larger float value:

binary: 00111101110011001100110011001101
value: 0.10000000149011612

The question is: given a float, is there a way to find the shortest decimal in the range of precision of the data type float?

std::string toShortestDecimal(float value) 
{  
   // ? should return "0.1" for 0.09999999403953552
}

Edit: I am using this converter.

My current idea is to scan the digits from left to right for first difference and then use everything to the left as the result.

For example:

00111111110101000111101011100001 = 1.659999966621399
00111111110101000111101011100010 = 1.6600000858306885

Since I am moving upwards, I can keep the larter of the first changing digit from the left, i.e. 6. The result is that 1.66 is a possible output. Now I need to repeat this in the other direction. Is this guaranteed to give the correct result?

Another poblem is how to increment a float to its nearest neighbor when both exponent and mantissa need to change.

Beginner
  • 5,277
  • 6
  • 34
  • 71

1 Answers1

1

This is a very inefficient, probably bugged implementation that should give a good start:

template<class T>
std::string convert(T value, int precision) {
    std::stringstream ss;
    ss << std::setprecision(100) << value;
    return ss.str();
}

template<class T>
std::string find_shortest(T value) {
    auto lower = convert(std::nextafter(value, -std::numeric_limits<T>::infinity()), 100);
    auto higher = convert(std::nextafter(value, std::numeric_limits<T>::infinity()), 100);

    int diff_idx = 0;
    while (lower[diff_idx] == higher[diff_idx]) ++diff_idx;
    lower = lower.substr(0, diff_idx+1);
    higher = higher.substr(0, diff_idx+1);
    if (std::abs(std::stod(lower.c_str()) - value) < 
        std::abs(std::stod(higher.c_str()) - value)) return lower;
    return higher;
}
orlp
  • 112,504
  • 36
  • 218
  • 315