我正在进行How to Think Like a Computer Scientist第5章的练习,并试图解决第3次练习:
写一个返回斜率的函数
slope(x1, y1, x2, y2)
穿过点(x1,y1)和(x2,y2)。一定要你的slope
的实现可以通过以下doctests:def slope(x1, y1, x2, y2): """ >>> slope(5, 3, 4, 2) 1.0 >>> slope(1, 2, 3, 2) 0.0 >>> slope(1, 2, 3, 3) 0.5 >>> slope(2, 4, 1, 2) 2.0 """
这是我提出的代码:
def slope(x1, y1, x2, y2):
"""
>>> slope(5, 3, 4, 2)
1.0
>>> slope(1, 2, 3, 2)
0.0
"""
sy = float(y1 - y2)
sx = float(x1 - x2)
return sy / sx
在第二次doctest上我得到-0.0
而不是0.0
...这令人困惑,因为我不知道-0.0
是一件事。我知道我可以使用abs()
获取绝对值,但是如果我确实有参数应该是负数,那么它就不会起作用。
还知道我可以在结果上设置一个条件,因此它使用绝对值或不是,但我想知道我是否只是在这里做错了。
答案 0 :(得分:2)
您可以通过在代码中交换slope()
和0.0
的顺序来编写y1 - y2
版本,为该doctest中的参数返回正数x1 - x2
:
def slope(x1, y1, x2, y2):
"""
>>> slope(5, 3, 4, 2)
1.0
>>> slope(1, 2, 3, 2)
0.0
"""
sy = float(y2 - y1)
sx = float(x2 - x1)
return sy / sx
>>> slope(1, 2, 3, 2)
0.0
如果争论相反,你仍会得到-0.0
:
>>> slope(3, 2, 1, 2)
-0.0
...但在doctests之外不太重要,因为0.0
和-0.0
在定义上是相同的。但是,如果您想确保始终返回正零,则只需add zero即可获得返回值:
def slope(x1, y1, x2, y2):
"""
>>> slope(5, 3, 4, 2)
1.0
>>> slope(1, 2, 3, 2)
0.0
"""
sy = float(y2 - y1)
sx = float(x2 - x1)
return sy / sx + 0 # prevent -0.0
>>> slope(1, 2, 3, 2)
0.0
>>> slope(3, 2, 1, 2)
0.0
"添加正零"技巧是任意的,本质上是神奇的行为,并且只是因为IEEE 754浮点标准说它必须:
当具有相反符号的两个操作数的总和(或具有相同符号的两个操作数的差异)是 正好为零,除非是所有舍入方向属性,该和(或差)的符号应为+0 roundTowardNegative;在该属性下,精确零和(或差)的符号应为-0。 但是,即使x为零,x + x = x - ( - x)也保持与x相同的符号。
- IEEE 754,第6.3节
有关浮点运算中有符号零的更多信息,请参见What Every Computer Scientist Should Know About Floating-Point Arithmetic。