我想知道如何编写自己的floor函数来向下舍入。
是否可以通过将表示逗号后面的数字的浮点数设置为0来实现此目的?
如果是,那么如何访问和修改这些位?
感谢。
答案 0 :(得分:4)
你可以对浮点数进行微调,但是正确地取决于确切知道浮点二进制表示是什么。对于大多数机器来说,这些天IEEE-754,这是相当直接的。例如,IEEE-754 32位浮点数有1个符号位,8个指数位和23个尾数位,因此您可以使用移位和掩码来提取这些字段并使用它们执行操作。所以做截断(向0舍入到整数)非常简单:
float trunc(float x) {
union {
float f;
uint32_t i;
} val;
val.f = x;
int exponent = (val.i >> 23) & 0xff; // extract the exponent field;
int fractional_bits = 127 + 23 - exponent;
if (fractional_bits > 23) // abs(x) < 1.0
return 0.0;
if (fractional_bits > 0)
val.i &= ~((1U << fractional_bits) - 1);
return val.f;
}
首先,我们提取指数字段,并使用它来计算后面的位数 小数点出现在数字中。如果有超过尾数的大小,那么我们只返回0.否则,如果至少有1,我们屏蔽(清除)许多低位。很简单。我们忽略了非正规,NaN和无限的她,但是这样做没问题,因为它们有所有0或全1的指数,这意味着我们最终将变形转换为0(它们会被捕获在第一个,如果,以及小正常数字),并保持NaN / Inf不变。
要做一个楼层,你还需要查看标志,并将负数向上舍入负向无穷大。
请注意,这几乎肯定比使用专用浮点指令慢,所以这种方法实际上只有在需要在没有本机浮点支持的硬件上使用浮点数时才有用。或者,如果你只是想玩,并了解这些东西如何在低水平工作。
答案 1 :(得分:3)
从头开始定义。不,将表示逗号后面的数字的浮点数的位设置为0将不起作用。如果你看一下IEEE-754,你会看到你基本上拥有表格中的所有浮点数字:
0.xyzxyzxyz 2^(abc)
因此,要实现地板,您可以获得xyzxyzxyz并向左移动abc + 1次。放下休息。我建议你阅读一个浮点数的二进制表示(上面的链接),这应该说明我建议的解决方案。
注意:您还需要处理符号位。你的号码的尾数偏离了127。
这是一个例子,假设你有数字pi:3.14 ......,你想得到3。
Pi以二进制表示为
0 10000000 10010010000111111011011
这转化为
sign = 0 ; e = 1 ; s = 110010010000111111011011
以上我直接来自Wikipedia。因为e是1.你会想要左移1 + 1 = 2,所以得到11 =&gt; 3.
答案 2 :(得分:0)
#include <iostream>
#include <iomanip>
double round(double input, double roundto) {
return int(input / roundto) * roundto;
}
int main() {
double pi = 3.1415926353898;
double almostpi = round(pi, 0.0001);
std::cout << std::setprecision(14) << pi << '\n' << std::setprecision(14) << almostpi;
}
3.1415926353898
3.1415
这几乎比你想出的任何一点点都要快。它适用于所有计算机(带浮动)而不只是一种类型。
答案 3 :(得分:0)
在加倍返回时强制转换为unsigned可以满足您的要求,但要在后台进行。这段简单的代码适用于任何积极的数字。
#include <iostream>
double floor(const double& num) {
return (unsigned long long) num;
}
答案 4 :(得分:0)
这已经在 tio.run (Try It Online) 和 onlinegdb.com 上进行了测试。该函数本身不需要任何 #include
文件,但为了打印出答案,我已经包含了 stdio.h
(在 tio.run 和 onlinegdb.com 中,而不是在这里)。这是:
long double myFloor(long double x) /* Change this to your liking: long double might
be float in your situation. */
{
long double xcopy=x<0?x*-1:x;
unsigned int zeros=0;
long double n=1;
for(n=1;xcopy>n*10;n*=10,++zeros);
for(xcopy-=n;zeros!=-1;xcopy-=n)
if(xcopy<0)
{
xcopy+=n;
n/=10;
--zeros;
}
xcopy+=n;
return x<0?(xcopy==0?x:x-(1-xcopy)):(x-xcopy);
}
这个函数在任何地方都有效(非常确定),因为它只是删除了所有非小数部分,而不是尝试处理浮点数部分。
浮点数的下限是小于或等于它的最大整数。以下是一些示例:
floor(5.7) = 5
floor(3) = 3
floor(9.9) = 9
floor(7.0) = 7
floor(-7.9) = -8
floor(-5.0) = -5
floor(-3.3) = -3
floor(0) = 0
floor(-0.0) = -0
floor(-0) = -0
注意:这几乎是我的 other answer 的精确副本,它回答了一个与这个问题基本相同的问题。