【问题标题】:How can I differentiate between zero and negative zero?如何区分零和负零?
【发布时间】:2019-12-16 10:49:17
【问题描述】:

我正在实现printf() 函数。几乎一切正常,但是当我调用 ft_printf("%f", -0.0) 时遇到问题。我的程序输出0.0 而不是-0.0。我不能使用任何库。

我检查消极性的条件只是“xDistinguish zero and negative zero 中找到了一个很有前途的解决方案。

这似乎可以解决我的问题:

double a = -0.0;
printf("%d\n", (*((long *)&a) == 0x8000000000000000));

我希望这个程序打印1,但在我的程序中,当我在代码中执行此操作时,它会输出0。我难以理解的部分是:*((long *)&a) 使数字与其十六进制对应物相当。

【问题讨论】:

  • 您违反了严格的别名规则,因此调用了未定义的行为。
  • 如果你想按照自己的方式做事,你必须给它加上一个字符数组的别名。
  • 您不能使用库有充分的理由吗?您将很难找到真正便携的解决方案。
  • “不使用任何不是我编码的东西”的规则表述得非常糟糕。 (并且您应该告诉我们规则的确切措辞及其例外情况,以便我们理解规则。)int main(void)int main(int argc, char *argv[]) 在 C 标准中给出,因此您没有编码,因此您无法定义main?使用math.hsignbit 宏绝对是测试浮点数符号的正确方法,它应该算作一项基本的语言功能,而不是像使用别人的代码那样受到限制。
  • 如果您不能使用signbit,则没有完全可移植的正确解决方案。您可以将表示某个对象x 的字节与表示-0.0. 的字节进行比较,这将在大多数实现中起作用(并且如果正确实现,则严格符合C 标准),但是一个实现可以有多个 -0 和 +0 表示,并且严格符合 C 代码无法了解和区分它们。

标签: c floating-point binary hex


【解决方案1】:

这类似于我完成的 Codewars Kata。诀窍是除以您要检查的数字是否为负零,如下所示:

int isPositiveZero(double a) {
    return 1/a == 1/0.0;
}

如果a 为负零,则除法为-infinity,如果a 为零,则为infinity

如果你想按照自己的方式做,试试这个:

(*((long *)&a) & 0x8000000000000000)

请注意,这违反了严格的别名规则,这会导致未定义的行为。这意味着您的程序可以做任何事情,从打印正确的结果到让您的计算机长出翅膀飞走。

如果您有 math.h 可用并且不反对使用标准 C 库中的宏,那么这个解决方案(使用 signbit)也可以工作(并且更便携):

#include <math.h>

int isPositiveZero(double a) {
    return a == 0.0 && !signbit(a);
}

【讨论】:

  • C 是否保证所有可能的double 表示都有正负无穷值?
  • @ThomasJager 我想是的。不过,它可能是 IEEE。
  • 我不反对 IEEE 754 浮点类型可以处理它。我的观点是,如果您不检查 IEEE 754 浮点是否在使用中,这不是一个可移植的解决方案。据我所知,C 不保证任何给定的实现。
  • 事实上,不,C保证浮点类型可以表示任何无穷大,正数或负数。它们通常会这样做,因为 IEEE 754 表示和算术相当普遍,但 C 不需要这些。
  • 不过,这肯定比 (*((long *)&amp;a) == 0x8000000000000000) 更便携。
【解决方案2】:

C 数学库(标准库的一部分)提供了a signbit macro,这绝对是检查浮点数符号的最简单和最便携的方法。如果您要求避免使用库是指第三方库,那么它将满足您的目的。

例子:

#include <math.h>
#include <stdio.h>

void putsign(double d) {
    if (signbit(d)) {
        putchar('-');
    } else {
        putchar('+');
    }
}

【讨论】:

  • “我不能使用任何库。”
  • signbit 是一个,因此不需要链接任何库。 Demo
  • @jl2210:另一方面,fputc 和朋友肯定需要stdio.h。如果不使用stdarg.h,就不可能实现诸如printf 之类的可变参数函数。所以至少有一部分标准库是存在的。 OP说有“某些例外”;知道它们是什么会很有用。
  • 根据 OP 正在实现的 printf 函数上的前缀 ft_ 判断,我敢打赌他们没有可用的 signbit 宏。搜索 libft 或 lib42 了解更多详情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-24
  • 2021-10-25
  • 1970-01-01
  • 2018-02-21
  • 2012-11-25
相关资源
最近更新 更多