将两个整数x和y有效地转换为浮点数x.y

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将两个整数x和y有效地转换为浮点数x.y相关的知识,希望对你有一定的参考价值。

给出两个整数X和Y,在C ++中将它们转换为X.Y浮点值的最有效方法是什么?

例如

 X = 3, Y = 1415 -> 3.1415

 X = 2, Y = 12   -> 2.12
答案

在撰写本文时,这是我的机器上所有将两个int转换为float的解决方案的一些鸡尾酒餐基准测试结果。

注意:我现在添加了自己的解决方案,该方法似乎效果很好,因此存在偏见!请仔细检查我的结果。

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:四核Intel Core i5-7600K速度/最小/最大:4000/800/4200 MHz
  • Devuan GNU / Linux 3
  • 内核:5.2.0-3-amd64 x86_64
  • GCC 9.2.1,带有标志:-O3 -march = native -mtune = native

Benchmark code(Github Gist)。

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

log10返回其参数的对数(以10为底)。对于1234,那将是3分。

打破这一点:

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

但是,正如@einpoklum所指出的,log(0)NaN,因此您必须进行检查。

#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;

请参阅以下可运行版本:https://onlinegdb.com/rkaYiDcPI

带有测试输出:

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

编辑

小修改可删除除法运算。

另一答案

我付出了一些努力来优化我以前的答案,并最终解决了这个问题。

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


另一答案

(重做的解决方案)

最初,我的想法是通过为整数编写这些函数的专用版本来提高10进制和10进制除法的性能。然后有@TarekDakhran的评论,关于对数字位数进行相同的操作。然后我意识到:这实际上是在做两次相同的事情……所以让我们将所有内容集成在一起。具体来说,这将使我们在运行时完全避免任何除法或取反:

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

附加说明:

  • 这将适用于y == 0;但是-不适用于x或y负值。使其适应负值非常容易,但也不是很昂贵。
  • 不确定这是否绝对最佳。也许对y的位数进行二进制搜索会更好?
  • 循环将使代码看起来更好;但是编译器需要将其展开。它会展开循环并事先计算所有这些浮点数吗?我不确定。
另一答案
double IntsToDbl(int ipart, int decpart)

    //The decimal part:
    double dp = (double) decpart;
    while (dp > 1)
    
        dp /= 10;
    

    //Joint boths parts
    return ipart + dp;

另一答案

简单快速的解决方案是将值xy都转换为字符串,然后将它们连接起来,然后将结果转换为如下所示的浮点数:

#include <string> 
#include <iostream>
std::string x_string = std::to_string(x);
std::string y_string = std::to_string(y);
std::cout << x_string +"."+ y_string ; // the result, cast it to float if needed
另一答案

正如,我们看到的答案很多,有许多可能的解决方案。另一种解决方案是使用std::stringstream生成格式化的输出并为小数部分指定字段。

我可以创建更多的变体,但是我需要更好的指定要求。

请参阅:

#include <iostream>
#include <sstream>
#include <iomanip>

double intsToDouble(int x, unsigned int fraction, unsigned int fractionWidth = 0U) 

    // We will use a stringstream zo hold the result as string
    std::ostringstream oss;

    // Create the expected output as string
    oss << x << '.' << std::setfill('0') << std::setw(fractionWidth) << fraction;

    // Convert the string to a double
    return stod(oss.str());


int main() 
    // some test cases
    std::cout << intsToDouble(3, 14) << '\n'
        << intsToDouble(3, 14, 5) << '\n'
        << intsToDouble(0, 0, 5) << '\n'
        << intsToDouble(1, 1, 2) << '\n'
        << intsToDouble(-10, 10, 3) << '\n';

    return 0;


另一答案

(基于OP尚未表明他们要使用float的事实的答案。]

最快(最有效)的方法是隐式执行此操作,但是实际上不执行任何操作(在编译器优化之后)。

也就是说,编写一个“伪浮点”类,其成员是小数点前后的x和y类型的整数;并让运算符执行您要对float进行的操作:operator +,operator *,operator /,operator-甚至pow(),log2(),log10()等的实现。

除非您计划要做的是将一个4字节的浮点数保存在某个地方供以后使用,否则,如果您具有下一个要使用的操作数,然后仅由x和y真正创建一个浮点数,几乎可以肯定会更快。 ,已经失去了精度并浪费了时间。

另一答案

尝试一下

#include <iostream>
#include <math.h>
using namespace std;
float int2Float(int integer,int decimal)

    float sign = integer/abs(integer);
    float tm = abs(integer), tm2 = abs(decimal);
    int base = decimal == 0 ? -1 : log10(decimal);
    tm2/=pow(10,base+1);
    return (tm+tm2)*sign;

int main()

    int x,y;
    cin >>x >>y;
    cout << int2Float(x,y);
    return 0;

版本2,尝试一下

#include <iostream>
#include <cmath>
using namespace std;

float getPlaces(int x)

    unsigned char p=0;
    while(x!=0)
    
        x/=10;
        p++;
    
    float pow10[] = 1.0f,10.0f,100.0f,1000.0f,10000.0f,100000.0f;//don't need more
    return pow10[p];

float int2Float(int x,int y)

    if(y == 0) return x;
    float sign = x != 0 ? x/abs(x) : 1;
    float tm = abs(x), tm2 = abs(y);
    tm2/=getPlaces(y);
    return (tm+tm2)*sign;

int main()

    int x,y;
    cin >>x >>y;
    cout << int2Float(x,y);
    return 0;

以上是关于将两个整数x和y有效地转换为浮点数x.y的主要内容,如果未能解决你的问题,请参考以下文章

在 C 中的某些整数上使用位操作中断将整数转换为浮点数

如何将大std :: string的一部分有效地转换为浮点数?

无法将字符串转换为浮点数:'CC6000'

Sympy - 生成 C 代码。将 Rational 转换为浮点数

Android - 如何正确地将字符串解析为浮点数(价格数字格式:整数、小数或两者兼有)

Python:将 2 个整数转换为浮点数