我有一个非常大的无符号二进制大整数,其规模为6*10^120。假设该大整数存储在一个由许多QWORD(8字节)无符号整数或几个YMM寄存器组成的结构体中。
我想用十进制(而不是二进制)科学记数法来显示它,比如6E120
。尾数总是1位数,并且必须是完整十进制表示法的首位数;将其截断为1个有效数字,而不是舍入到最接近的数字。指数始终为3位数字。格式为aExyz,如8 E095。
求数量级(10的幂)和小数点前几位最省时(最快)的算法是什么?我问的是算法,不是程序,我自己写。
这将是在MASM 64汇编语言。如果有指令,可以帮助像位操作或FPU/SSE/AVX 512技巧,请建议他们。
这不是一个高级程序,所以任何包含第三方库或高级语言构造的响应都没有帮助。我知道某个算法涉及许多除法。这些在ASM中是昂贵的,所以我正在寻找替代方法。我知道如何从二进制转换为十进制,然后转换为科学记数法。我正在努力避免中间的步骤。
1条答案
按热度按时间3qpi33ja1#
假设最大可能值小于1E154,因此所有值都适合512位,那么我猜想答案 * 可能 * 是:
powers_of_10
。(#ops~0)clz
)(#ops〈~10)(max-bits - number_of_leading_zeroes) / 3.32192809489
可以很好地估计十进制数字的最终个数。这也是一个接近10的幂的很好的估计。(#ops~2)powers_of_10
,直到找到小于您的值的最大10次幂(#ops~8)。uint64
s)double(input)/double(power_of_ten)
将在一个除法中完成。loop_count-1
E
power_of_ten_index
。(操作数约为4)如果你愿意牺牲指数和尾数的精确度,那么剩下的16个操作完全忽略了低位。
性能
在不写出最终实现的情况下,很难猜测性能,而使用较大的LUT、缓存,因此程序的其余部分就成为一个因素,但这里是初步数据:https://quick-bench.com/q/53k-xSQz7y4iCO7ny66Dz2w62dQ(我运行了几次,试图消除离群值)
在我的测试中,最快的组合似乎(毫不奇怪)是:
powers_of_ten
来确认指数。从这个基线,我们可以看到:
powers_of_ten
看起来对平均时间没有明显的影响,只要你还使用浮点数来猜测尾数。如果你不使用浮点数来猜测尾数,那么尾数计算将花费更长的时间。这意味着它不会显著增加平均精度,可以跳过它以最小化代码大小。值得注意的是,所有这些都比将bigint转换为
double
然后使用printf("%.0E",value);
快约4倍(本人不保证任何此代码结果的准确性)