Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficiently convert two Integers x and y into the float x.y

Given two integers X and Y, whats the most efficient way of converting them into X.Y float value in C++?

E.g.

 X = 3, Y = 1415 -> 3.1415

 X = 2, Y = 12   -> 2.12
like image 264
tunafish24 Avatar asked Apr 05 '20 18:04

tunafish24


People also ask

How do you convert an integer to a float in Java?

Use the floatValue() Function to Convert an Integer Into a Float in Java. The floatValue() function can convert a given integer value into float.

How do you convert long to float?

Long class has the following methods for converting long type value to other primitive types. byte byteValue() returns the value of this Long as a byte. double doubleValue() returns the value of this Long as a double. float floatValue() returns the value of this Long as a float.

How do you convert floating to int and rounding?

round() method, which converts float to its nearest integer by adding +0.5 to it's value and then truncating it.

How to convert x to Y in Excel?

Given two positive integers X and Y, the task is to check if X can be converted to Y or not by repeatedly changing the value of X to (3 * X / 2) ( if X is even) or (X – 1). If it is possible to convert X into Y, then print “Yes”.

How to get the integer part of a float value?

Then, we get the integer part of the float value by shifting operations as it was mentioned above. Note that we use the bitwise OR operator ( |) as a way of “adding” the leading one and the lower order bits of the frac field (e.g. 100 | 001 = 101 ). Finally, we modify the bit encoding for negative values.

What does the expression ~x+1 mean in float_f2i?

The expression ~x+1 is just a binary operation that yields -x in two’s complement representation. Putting all of the pieces together in the float_f2i function, we get: /* Compute (int) f. In order to handle the bit-level representation of float values with bitwise operators, we use the unsigned datatype which we call float_bits.

How do you aggregate integral and decimal numbers into a float?

As far as I understand, you have an integral part (x), and a decimal part (y), and you want to aggregate that into a floating point number. You can first make the decimal part by dividing itself by 10 until it gets lower than 1, and then add it to your integral part (properly converted to float)


3 Answers

(reworked solution)

Initially, my thoughts were improving on the performance of power-of-10 and division-by-power-of-10 by writing specialized versions of these functions, for integers. Then there was @TarekDakhran's comment about doing the same for counting the number of digits. And then I realized: That's essentially doing the same thing twice... so let's just integrate everything. This will, specifically, allow us to completely avoid any divisions or inversions at runtime:

inline float convert(int x, int y) {
    float fy (y);
    if (y == 0)  { return float(x); }
    if (y >= 1e9) { return float(x + fy * 1e-10f); }
    if (y >= 1e8) { return float(x + fy * 1e-9f);  }
    if (y >= 1e7) { return float(x + fy * 1e-8f);  }
    if (y >= 1e6) { return float(x + fy * 1e-7f);  }
    if (y >= 1e5) { return float(x + fy * 1e-6f);  }
    if (y >= 1e4) { return float(x + fy * 1e-5f);  }
    if (y >= 1e3) { return float(x + fy * 1e-4f);  }
    if (y >= 1e2) { return float(x + fy * 1e-3f);  }
    if (y >= 1e1) { return float(x + fy * 1e-2f);  }
                    return float(x + fy * 1e-1f); 
}

Additional notes:

  • This will work for y == 0; but - not for negative x or y values. Adapting it for negative value is pretty easy and not very expensive though.
  • Not sure if this is absolutely optimal. Perhaps a binary-search for the number of digits of y would work better?
  • A loop would make the code look nicer; but the compiler would need to unroll it. Would it unroll the loop and compute all those floats beforehand? I'm not sure.
like image 179
einpoklum Avatar answered Nov 12 '22 05:11

einpoklum


float sum = x + y / pow(10,floor(log10(y)+1));

log10 returns log (base 10) of its argument. For 1234, that'll be 3 point something.

Breaking this down:

log10(1234) = 3.091315159697223
floor(log10(1234)+1) = 4
pow(10,4) = 10000.0
3 + 1234 / 10000.0 = 3.1234. 

But, as @einpoklum pointed out, log(0) is NaN, so you have to check for that.

#include <iostream>
#include <cmath>
#include <vector>

using namespace std;

float foo(int x, unsigned int y)
{
    if (0==y)
        return x;

    float den = pow(10,-1 * floor(log10(y)+1));
    return x + y * den; 
}

int main()
{
    vector<vector<int>> tests
    {
     {3,1234},
     {1,1000},
     {2,12},
     {0,0},
     {9,1}
    };

    for(auto& test: tests)
    {
        cout << "Test: " << test[0] << "," << test[1] << ": " << foo(test[0],test[1]) << endl;
    }

    return 0;
}

See runnable version at: https://onlinegdb.com/rkaYiDcPI

With test output:

Test: 3,1234: 3.1234
Test: 1,1000: 1.1
Test: 2,12: 2.12
Test: 0,0: 0
Test: 9,1: 9.1

Edit

Small modification to remove division operation.

like image 39
3Dave Avatar answered Nov 12 '22 07:11

3Dave


I put some effort into optimizing my previous answer and ended up with this.

inline uint32_t digits_10(uint32_t x) {
  return 1u
      + (x >= 10u)
      + (x >= 100u)
      + (x >= 1000u)
      + (x >= 10000u)
      + (x >= 100000u)
      + (x >= 1000000u)
      + (x >= 10000000u)
      + (x >= 100000000u)
      + (x >= 1000000000u)
      ;
}

inline uint64_t pow_10(uint32_t exp) {
  uint64_t res = 1;
  while(exp--) {
    res *= 10u;
  }
  return res;
}

inline double fast_zip(uint32_t x, uint32_t y) {
  return x + static_cast<double>(y) / pow_10(digits_10(y));
}

like image 23
Tarek Dakhran Avatar answered Nov 12 '22 06:11

Tarek Dakhran