【问题标题】:Using 0b representation to print (printf) float使用 0b 表示打印 (printf) 浮点数
【发布时间】:2017-02-14 09:19:40
【问题描述】:

我正在尝试用二进制表示小数,然后将其打印为浮点数。我已经完成了定点到浮点的转换。

十进制数:-342.265625

定点:-101010110.010001

32 位浮点数:11000011101010110010001000000000

64 位浮点数(双精度):1100000001110101011001000100000000000000000000000000000000000000

*我已经用 IEEE 754 转换器仔细检查过

*我也知道 printf 将浮点数更改为双精度以打印它们,但是将其声明为双精度应该可以吗?我以为……?

代码:

int main()
{

  float floaty = 0b11000011101010110010001000000000;
  double doubley = 0b1100000001110101011001000100000000000000000000000000000000000000;
  printf("Float: %f\n", floaty);
  printf("Double: %lf\n", doubley);

}

输出:

Float: 3282772480.000000
Double: 13868100853597995008.000000

编译器是gcc,标准是c99

【问题讨论】:

  • 0b 必须是 gcc 扩展。如果您能找到有关它如何与浮点初始化一起工作的文档,那就太好了。
  • @CST-Link 打印floaty应该没关系
  • @CST-Link 在 C 中,尾随参数受默认参数提升的影响,它将浮点数提升为双精度。说明符 f 和 lf 对 double 或 float 有效。 OP 正在使用最好的选择。
  • @CST-Link printf 格式 %f 用于 double 并且任何 float 参数都提升为 double,其方式与 %d a char 相同参数被提升为int
  • 哈哈...显然我am错了...谢谢大家睁开眼睛。

标签: c binary floating-point printf


【解决方案1】:

问题是编译器试图帮助你。顺便说一下,您的文字 (0b1...) 是一个非标准扩展名,应该写为 (0x...),它被视为文字。然后,编译器会尽力将这些值适合您将它们转换为的变量。因此,它会产生非常大的值,等于您的文字的整数值。

要直接分配变量的值,您必须使用联合(或指针,如果您不介意失去一点可移植性)。此代码有效:

#include <stdint.h>

union floatint {
    float f;
    uint32_t i;
};

union doubleint {
    double d;
    uint64_t i;
};    

int main()
{
  floatint floaty;
  doubleint doubley;
  floaty.i = 0xC3AB2200;
  doubley.i = 0xC075644000000000; 
  printf("Float: %f\n", floaty.f); // implementation-defined, in your case IEEE 754
  printf("Double: %lf\n", doubley.d); // ditto

}

请注意,这正是联合的定义,两个(或更多)类型共享相同的表示,但处理方式不同。

【讨论】:

  • 谢谢@LambdaBeta,有没有办法用我最初发布的二进制值来表达它们?
  • 指针转换(float*uint32_t*)是 UB 的来源。通常,union 如果编码得当,可以解决很多问题。
  • 没错,我把 union 和 aliasing 搞混了,这很尴尬。这很有趣,因为我最初的测试可执行文件实际上使用了一个联合来证明代码可以工作,然后我使用别名重写了它以更加简洁。它的联合是IB,别名是UB。我会相应地编辑我的答案。
  • 或者(关于使用非标准二进制文字的模警告):floaty = (floatint){.i = 0b11000011101010110010001000000000}; 实际上,通常首选使用十六进制浮点常量:floaty.f = -0x1.564400p+8f;
【解决方案2】:

来自 gcc 的documentation

这些常量的类型遵循与八进制或八进制相同的规则 十六进制整数常量,所以像‘L’或‘UL’这样的后缀可以是 已申请。

因此,您分配给 float 和 double 的二进制数实际上是 整数类型,并且不直接映射到您分配的基础类型的位模式。

换句话说,这个:

 float floaty = 0b11000011101010110010001000000000;
 double doubley = 0b1100000001110101011001000100000000000000000000000000000000000000;

相当于:

 float floaty = 3282772480;
 double doubley = 13868100853597995008;

【讨论】:

  • 有没有办法用这些二进制值来表达它们?
  • @ZacTaylor C 不提供在位级别操作的直接规定;最低可寻址单元是 C 中的 byte。您可以按照 2501 的建议进行操作,这将适用于大多数现代系统。
【解决方案3】:

您可以使用二进制常量进行更多工作。

我们将不得不假设使用 IEEE 754 表示的浮点数,并且系统是小端:

uint32_t value = 0b11000011101010110010001000000000;
float f;
memcpy( &f , &value , sizeof( f ) );
printf( "%f\n" , f );

【讨论】:

  • 谢谢@2501,我希望它能够工作,我现在是一个非常幸福的人!
  • @ZacTaylor 只要确保你记录并断言假设。
  • 我不确定你的意思?
  • @ZacTaylor 该代码可能会在某些系统上导致未定义的行为。
  • 好的,我知道了!再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-04
  • 2016-09-02
  • 1970-01-01
  • 2015-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多