将两个整数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;
简单快速的解决方案是将值x
和y
都转换为字符串,然后将它们连接起来,然后将结果转换为如下所示的浮点数:
#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的主要内容,如果未能解决你的问题,请参考以下文章
如何将大std :: string的一部分有效地转换为浮点数?
Sympy - 生成 C 代码。将 Rational 转换为浮点数