c 改变双精度数的指数
Posted
技术标签:
【中文标题】c 改变双精度数的指数【英文标题】:c change the exponent of a double 【发布时间】:2014-09-07 15:17:07 【问题描述】:假设我有一个double a = 0.3;
。在不使用 pow()
等数学函数或手动相乘的情况下,我如何能够更改变量的指数。
我猜我必须使用指针访问变量的内存地址,找到指数并手动更改它。但是我该如何做到这一点呢?
请注意,这是在 8 位系统上,我正在尝试找到一种更快的方法将数字乘以 10^12、10^9 , 10^6 或 10^3。
最好的问候!
【问题讨论】:
我认为你不会有太大的成功。典型浮点的指数部分是 二进制 指数,而不是以 10 为底的指数。 看到double
是一个 二进制 浮点数,调整指数位将无助于乘以 10 的幂,只能乘以 2 的幂。跨度>
您需要一个准确的结果,还是一个近似值对您来说足够好?
正如其他人所说,在这里摆弄比特对您没有帮助。但是如果你不使用pow
函数来计算你的因子10^x,你可能会加快你的计算速度。 (如果你现在正在这样做,那就是。)
@user1806687:您可以使用查找表,例如:double decpow[] = 1, 10, 100, 1000, ...
并使用decpow[x]
而不是pow(10, x)
。 (当然,这需要x
的非负整数值。但也有类似的解决方案取决于您的需要。似乎您只使用与单位前缀相关的十次方,如千-、兆-等)
【参考方案1】:
注意a*10^3 = a*1000 = a*1024 - a*16 - a*8 = a*2^10 - a*2^4 - a*2^3
。
所以你可以计算a*10^3
如下:
将11个指数位读入int exp
将 52 个小数位读入double frac
计算double x
,以exp+10
为指数,frac
为分数
计算double y
,以exp+4
为指数,frac
为分数
计算double z
,以exp+3
为指数,frac
为分数
计算输出为x-y-z
,如果a < 0
,别忘了加上符号位
您可以对其他选项(a*10^6
、a*10^9
和 a*10^12
)使用类似的方法...
您可以通过以下方式以“干净”的方式完成所有工作:
double MulBy1000(double a)
double x = a;
double y = a;
double z = a;
unsigned long long* px = (unsigned long long*)&x;
unsigned long long* py = (unsigned long long*)&y;
unsigned long long* pz = (unsigned long long*)&z;
*px += 10ULL << 52;
*py += 4ULL << 52;
*pz += 3ULL << 52;
return x - y - z;
请注意,我不确定这段代码是否违反了严格的别名规则。
【讨论】:
当指数 > minimum_exponent 时,frac
需要更多的工作来解释隐含的1
位。
@chux:我同意。这只是一个大概的思路,具体的实现细节留给OP去处理……谢谢。
a 永远不会小于 0。那么,如何读取指数位和分数位?
@user1806687:请注意第二次更新(给出乘以 10^3
的完整实现)。
@user1806687:不客气,这对我来说也是一个好习惯 :)【参考方案2】:
一个数乘以 10 相当于
a) 将原始数字乘以 2 b) 将原始数字乘以 8 c) 将 (a) 和 (b) 的结果相加。这是可行的,因为 to 是二进制的 1010
。
因此,一种方法是增加指数(对于 (a)),将 3 添加到指数(对于 (b)),然后添加结果。
要乘以 10^n,重复上述 n 次。或者计算出 1,000、1,000,000 等的二进制表示,并添加相关的 1。您可以通过注意 1000 例如 1024(例如)是 1024 - 16 - 8 来让事情变得更容易,即
a) 将原始的指数加 10 以乘以 1024 b) 将原始的指数加 4 以乘以 16 c) 将原始的指数加 3 以乘以 8 d) 从 (a) 减去 (b) 和 (c) 得到答案。同样,您可以多次执行 10^6、10^9 等。
对于 n 的快速近似值和 3 的倍数的幂,只需将 10n/3 添加到指数(如 1024 ~= 1000)
【讨论】:
【参考方案3】:为了好玩,一个简单的递归解决方案。
double ScalePower10(double x, unsigned power)
if (power <= 1)
if (power == 0) return x;
return x * 10.0;
double y = ScalePower10(x, power/2);
y = y*y;
if (power%2) y *= 10.0;
return y;
【讨论】:
嗨 Chux。我认为 OP 是(隐含地)试图避免浮点运算。除此之外,尽管您的解决方案对于所有可能的指数都是通用的,但我认为 OP 要求的是一个非常具体的解决方案(对于a*10^3
、a*10^6
、a*10^9
和 a*10^12
)。鉴于这一事实,OP 正在寻求一种优化的解决方案,即以非通用解决方案的价格获得最佳性能。以上是关于c 改变双精度数的指数的主要内容,如果未能解决你的问题,请参考以下文章