1

I'm working on the exercises from Chapter 5 of How to Think Like a Computer Scientist, and am trying to solve the 3rd exercise:

Write a function slope(x1, y1, x2, y2) that returns the slope of the line through the points (x1, y1) and (x2, y2). Be sure your implementation of slope can pass the following 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
    """

This is the code I've come up with:

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

On the 2nd doctest I'm getting -0.0 instead of 0.0 … which is confusing, since I didn't know -0.0 was a thing. I know I can use abs() to get the absolute value but, then if I do have parameters that should come out to a negative number, it won't work.

Also know I can set a condition on the result so it uses the absolute value or doesn't, but I'm wondering if I'm just doing something wrong here.

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
dan
  • 401
  • 1
  • 5
  • 10
  • 1
    Is this actually a problem? `-0.0` compares as equal to `+0.0`... – jasonharper Mar 11 '18 at 21:49
  • @jasonharper for the exercise I'm trying to solve, yes it is a problem. The reason being the exercise is to make sure the function passes all the doctests. With that code, it fails the 2nd doctest since it is excepting 0.0 and not -0.0 – dan Mar 11 '18 at 21:53
  • Can't you just add in a check to see if the number is `-0.0`, if that's the only case you are struggling with? – user3483203 Mar 11 '18 at 22:00
  • 1
    That's strange - whatever is verifying the doctests had to *go out of its way* to distinguish positive and negative zeroes, even though it shouldn't make any difference. Anyway, adding `0.0` to the return value should fix the "problem". – jasonharper Mar 11 '18 at 22:09
  • @jasonharper doctest cares whether [the output is exactly as specified in the test](https://docs.python.org/2/library/doctest.html#warnings), not whether values are considered equal. – Zero Piraeus Mar 11 '18 at 23:44
  • 2
    FYI, +0 and −0 are exactly the same value, so there is nothing mathematically wrong with a −0 result when zero is expected. The IEEE 754 floating-point standard distinguishes them in part so that, when underflow occurs, a program can examine the sign bit to see on which side of zero the mathematical result was. Nothing testing mathematical results should care about the sign when the correct result is exactly zero. A test suite should only report a problem if the number needs to be formatted in a particular way for some reason, such as to avoid confusing humans, since they may be put off by it. – Eric Postpischil Mar 12 '18 at 00:40

1 Answers1

2

You can write a version of slope() that returns positive 0.0 for the arguments in that doctest by swapping the order of y1 - y2 and x1 - x2 in your code:

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

You'll still get -0.0 if the arguments are reversed:

>>> slope(3, 2, 1, 2)
-0.0

… but outside of doctests that's unlikely to matter, since 0.0 and -0.0 are equal by definition. However, if you want to be sure of always returning a positive zero, you can just add zero to your return value:

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

The "add positive zero" trick is arbitrary and essentially magical behaviour, and works simply because the IEEE 754 floating point standard says it must:

When the sum of two operands with opposite signs (or the difference of two operands with like signs) is exactly zero, the sign of that sum (or difference) shall be +0 in all rounding-direction attributes except roundTowardNegative; under that attribute, the sign of an exact zero sum (or difference) shall be −0. However, x + x = x − (−x) retains the same sign as x even when x is zero.

— IEEE 754, Section 6.3

More information about signed zero in floating point arithmetic can be found at What Every Computer Scientist Should Know About Floating-Point Arithmetic.

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
  • 3
    It might be nice to explain why adding +0 works. To the floating-point novice, it may seem like some unexplained magic. But IEEE 754 has specific rules for managing the sign, such as that multiplication XORs the sign, and one of the rules is that −0 + +0 produces +0. (And I am not sure there is any necessary reason for that, other than that you have to pick one to be the result, and humans like +.) – Eric Postpischil Mar 12 '18 at 00:44
  • @EricPostpischil how's this? (to the best of my knowledge the behaviour is, as you say, arbitrary; the standard doesn't seem to justify it on any grounds other than "because we say so", at any rate). – Zero Piraeus Mar 12 '18 at 12:46