【问题标题】:In C89, how can I truncate and split a double precision floating point into two 32-bit words?在 C89 中,如何将双精度浮点数截断并拆分为两个 32 位字?
【发布时间】:2016-02-29 13:16:36
【问题描述】:

当面向 C99 时,我可以使用以下代码截断 double 值并将其拆分为两个 32 位整数:

#include <stdint.h>

void split(double d, unsigned long *most_significant_word, unsigned long *least_significant_word)
{
   uint64_t i = (uint64_t)d;
   *most_significant_word = i >> 32;
   *least_significant_word = i & 0xffffffff;
}

然而,C89 似乎没有定义 64 位整数类型,所以我不能使用编译器来执行截断。即使不需要截断(该值已经表示一个整数),我也不能使用像 &amp;&gt;&gt; 这样的位运算符,因为它们不适用于 double 值。

那么,上面的 split() 函数如何在纯 C89 中实现(因此不依赖于 64 位整数),返回构成存储在 @987654327 中的 53 位整数的 21/32 位字@值?

【问题讨论】:

  • C89 不提供stdint.h。您需要执行特定的细节。由于不提供long long,如何读取64位值?
  • @Olaf:但是,C89 要求 long 至少为 32 位宽。对于输出,使用unsigned long 应该没问题。
  • @MatteoItalia:这与我的评论有何矛盾?我想我清楚地写了它是特定于实现的,并非不可能。仅仅依靠long 拥有32 位是非常错误的。请参阅 POSIX64!不过,更大的问题是 64 位类型。
  • @Olaf:我以为你指的是输出类型; 64位类型无关紧要,您可以在double中进行所有数学运算。
  • @rubenvb:您的问题包括它的答案:“假设 int 是 32 位宽”。请阅读定义的实现是什么意思!我没有心情再重复一遍。

标签: c c99 c89 ansi-c


【解决方案1】:

忽略符号(就像原始代码一样)它应该像这样简单:

void split(double d, unsigned long *most_significant_word, unsigned long *least_significant_word)
{
   *most_significant_word = d/4294967296.; // d>>32 in double
   *least_significant_word = fmod(d, 4294967296.);
}

要考虑负数,对绝对值进行运算,然后计算二进制补码:

void split(double d, unsigned long *most_significant_word, unsigned long *least_significant_word)
{
   double dabs = d < 0 ? -d : d;
   *most_significant_word = dabs/4294967296.;
   *least_significant_word = fmod(dabs, 4294967296.);
   if (d < 0) {
       *most_significant_word = ~*most_significant_word;
       *least_significant_word = ~*least_significant_word + 1;
       if (!*least_significant_word) *most_significant_word += 1;
   }
}

【讨论】:

  • 这真的很简单,谢谢。给我几分钟来测试一下。修改这个答案是否会很复杂,以便在负数的情况下单词包含二进制补码?
  • 对于优化程度较低的 C 编译器,最好使用 exp2() 而不是 pow()
  • @MarkDickinson:无符号整数溢出定义明确,并且(我认为)执行 OP 所期望的操作,即采用存储在 d 中的整数的最低 32 位,就像原始代码一样.当然,如果他想提取双精度的原始位,那就完全不同了(最好使用memcpy 完成),但这不是他提供的代码所做的。
  • @FUZxxl:我直接将其更改为 double 字面量。
  • @Thiago de Arruda 我希望 Matteo Italia 喜欢你的编辑。我不会感谢其他人对一个活跃的问题进行如此大的编辑。尤其是在它被接受之后。
猜你喜欢
  • 2021-01-25
  • 2015-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多