将2x32位大整数除以1000
Dividing a 2x32 bit big integer by 1000
我在两个32位变量中存储了大量的时间(微秒)。我需要帮助,如何将微秒时间更改为毫秒,这样我就可以将差值的结果存储在32位数字中。
更多详细信息:我在两个32位变量中有一次。其中一个变量具有较高的有效位,而另一个变量则具有较低的有效位。这个时间的分辨率是微秒,所以我想把它改为毫秒。那么,如何将存储在两个变量中的数字进行除法。
如果您没有64位类型,可以按照以下方式进行:
uint32_t higher, lower; // your input
lower /= 1000;
lower += (higher % 1000) * 4294967L; // approximate 2^32 / 1000
higher /= 1000;
如果结果符合lower
本身,则higher
应为0
。
请注意,正如@Mikhail所指出的,这个解决方案是近似的,误差为0.296 * higher + 2
ms(除非我遗漏了什么)。
如果真的想要更好的精度而不关心效率,可以在中间使用一些浮点运算,并正确地对结果进行四舍五入。我怀疑这是否值得付出努力:
uint32_t higher, lower; // your input
// simpler without a helper variable
if (lower % 1000 >= 500)
{
lower /= 1000;
++lower;
}
else
lower /= 1000;
lower += round((higher % 1000) * 4294967.296); // 2^32 / 1000
higher /= 1000;
round()
需要include <cmath>
。
需要注意的是,@Mikhail在这种情况下的解决方案可能更好,可能更快。虽然对我来说太复杂了。
如果你有一个64位类型,你可以将分割值转换为:
uint64_t whole_number = higher;
whole_number <<= 32;
whole_number |= lower;
然后您可以像往常一样使用whole_number
。
请注意,如果您只需要一个差值,那么在实际除法之前减去这些值会更快。
假设您知道哪个值更大:
uint32_t higher1, lower1; // smaller value
uint32_t higher2, lower2; // bigger value
uint32_t del_high = higher2 - higher1;
uint32_t del_low = lower2 - lower1;
if (lower2 < lower1)
--del_high;
现在,您可以像前面解释的那样转换结果。或者如果运气好的话,del_high
将是0
(如果差值小于2^32μs),您将在del_low
中得到结果(以μs为单位)。
最简单的方法是使用64位整数类型,但我认为您无法做到这一点。由于您希望答案为32位整数,微秒的高阶值不能大于999,或者除以1000后将不适合32位。因此,使用999 * 2^32 + (2^32 - 1) = 4294967295999
操作的微秒数越大。它给你13个十进制数字,你可以使用double
来处理精确除法。
如果您由于某种原因被迫只使用32位整数,MichałGórny的答案会给您一个近似解决方案。例如,对于whole_number = 1234567890123
,它将给出1234567805
的结果。因为最大32位int在1000上的除法有一个提醒。
用32位整数得到精确答案的唯一方法是使用长算术。它要求长数字存储在一种可以扩展为存储提醒的类型中。您必须将两个32位整数拆分为四个16位数字。在那之后,你可以把它像纸上一样分开,你有足够的碎片来存储提醒。参见micro2milli
:的代码
#include <iostream>
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;
const uint32 MAX_INT = 0xFFFFFFFF;
uint32 micro2milli(uint32 hi, uint32 lo)
{
if (hi >= 1000)
{
throw std::runtime_error("Cannot store milliseconds in uint32!");
}
uint32 r = (lo >> 16) + (hi << 16);
uint32 ans = r / 1000;
r = ((r % 1000) << 16) + (lo & 0xFFFF);
ans = (ans << 16) + r / 1000;
return ans;
}
uint32 micro2milli_simple(uint32 hi, uint32 lo)
{
lo /= 1000;
return lo + (hi % 1000) * 4294967L;
}
void main()
{
uint64 micro = 1234567890123;
uint32 micro_high = micro >> 32;
uint32 micro_low = micro & MAX_INT;
// 1234567805
std::cout << micro2milli_simple(micro_high, micro_low) << std::endl;
// 1234567890
std::cout << micro2milli(micro_high, micro_low) << std::endl;
}
首先,将两个变量放入3中,每个变量有22个有效位。
uint32_t x0 = l & 0x3FFFFF;
uint32_t x1 = ((l >> 22) | (h << 10)) & 0x3FFFFF;
uint32_t x2 = h >> 12;
现在进行除法(每个x?有10个可用位,1000<2^10=1024,因此不可能溢出)
uint32_t t2 = x2 / 1000;
x1 |= (x2 % 1000) << 22;
uint32_t t1 = x1 / 1000;
x0 |= (x1 % 1000) << 22;
uint32_t t0 = (x0 + 500) / 1000;
/* +0 for round down, +500 for round to nearest, +999 for round up */
现在把事情重新组合起来。
uint32_t r0 = t0 + t1 << 22;
uint32_t r1 = (t1 >> 10) + (t2 << 12) + (r0 < t0);
使用相同的技术,但四个变量保持16位,您可以对高达65535的除数执行此操作。然后,用32位的算术运算就变得更难了。
假设不能使用64位int,我建议使用多精度库,如GMP。
- 如何反转整数参数包
- enum是C++中的宏变量还是整数变量
- 努力将整数转换为链表。不知道我在这里做错了什么
- 整数不会重复超过随机数
- 在C++中手动调整数组大小
- 检查输入是否不是整数或数字
- C++使用整数的压缩数组初始化对象
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- 如何只允许用户输入正整数
- 如何在c++中从文本文件中逐行读取整数
- C++:如何循环通过向量中的整数元素
- 我可以信任表示整数的浮点或双精度来保持精度吗
- 序列化,没有库的整数,得到奇怪的结果
- 以下程序中最大 int 1000 000(在 int 范围内)的整数溢出
- 将2x32位大整数除以1000
- 输入10^1000范围内的整数
- 编写程序生成1000个0-49范围内的随机整数.(c++)
- 对1000个整数的数组进行排序