Efficiently convert two Integers x and y into the

2020-07-11 05:53发布

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

9条回答
【Aperson】
2楼-- · 2020-07-11 06:34

Here are some cocktail-napkin benchmark results, on my machine, for all solutions converting two ints to a float, as of the time of writing.

Caveat: I've now added a solution of my own, which seems to do well, and am therefore biased! Please double-check my results.

Test                              Iterations    ns / iteration
--------------------------------------------------------------
@aliberro's conversion v2         79,113,375                13
@3Dave's conversion               84,091,005                12
@einpoklum's conversion        1,966,008,981                 0
@Ripi2's conversion               47,374,058                21
@TarekDakhran's conversion     1,960,763,847                 0
  • CPU: Quad Core Intel Core i5-7600K speed/min/max: 4000/800/4200 MHz
  • Devuan GNU/Linux 3
  • Kernel: 5.2.0-3-amd64 x86_64
  • GCC 9.2.1, with flags: -O3 -march=native -mtune=native

Benchmark code (Github Gist).

查看更多
孤傲高冷的网名
3楼-- · 2020-07-11 06:34

If you want something that is simple to read and follow, you could try something like this:

float convertToDecimal(int x)
{
  float y = (float) x;
  while( y > 1 ){
    y = y / 10;
  }
  return y;
}

float convertToDecimal(int x, int y)
{
  return (float) x + convertToDecimal(y);
}

This simply reduces one integer to the first floating point less than 1 and adds it to the other one.

This does become a problem if you ever want to use a number like 1.0012 to be represented as 2 integers. But that isn't part of the question. To solve it, I would use a third integer representation to be the negative power of 10 for multiplying the second number. IE 1.0012 would be 1, 12, 4. This would then be coded as follows:

float convertToDecimal(int num, int e)
{
  return ((float) num) / pow(10, e);
}

float convertToDecimal(int x, int y, int e)
{
  return = (float) x + convertToDecimal(y, e);
}

It a little more concise with this answer, but it doesn't help to answer your question. It might help show a problem with using only 2 integers if you stick with that data model.

查看更多
Summer. ? 凉城
4楼-- · 2020-07-11 06:39

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));
}

查看更多
狗以群分
5楼-- · 2020-07-11 06:45
double IntsToDbl(int ipart, int decpart)
{
    //The decimal part:
    double dp = (double) decpart;
    while (dp > 1)
    {
        dp /= 10;
    }

    //Joint boths parts
    return ipart + dp;
}
查看更多
Deceive 欺骗
6楼-- · 2020-07-11 06:46

(Answer based on the fact that OP has not indicated what they want to use the float for.)

The fastest (most efficient) way is to do it implicitly, but not actually do anything (after compiler optimizations).

That is, write a "pseudo-float" class, whose members are integers of x and y's types before and after the decimal point; and have operators for doing whatever it is you were going to do with the float: operator+, operator*, operator/, operator- and maybe even implementations of pow(), log2(), log10() and so on.

Unless what you were planning to do is literally save a 4-byte float somewhere for later use, it would almost certainly be faster if you had the next operand you need to work with then to really create a float from just x and y, already losing precision and wasting time.

查看更多
该账号已被封号
7楼-- · 2020-07-11 06:50

(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.
查看更多
登录 后发表回答