News for hackers. Stuff that matters.
Re:1/0 = 0 by Veedrac on Friday August 10, 2018 @06:37PM (#17737197)
My comment from when this came up on Reddit, slightly edited for context:

`/`-by-0 is just an operation and it tautologically has the semantics assigned to it. The question is whether the specific behaviour will cause bugs, and on glance that doesn't sound like it would be the case.

Principally, division is normally (best guess) used in cases where the divisor obviously cannot be zero; cases like division by constants are very common, for example. The second most common usage (also best guess) is to extract a property from an aggregate, like `average = sum / count` or `elem_size = total_size / count`. In these cases the result is either a seemingly sane default (`average = 0` with no elements, `matrix_width = 0` when zero-height) or a value that is never used (eg. `elem_size` only ever used inside a loop iterated zero times).

It seems unlikely to me that `/` being a natural extension of division that includes division by zero would be nontrivially error-prone. Even when it does go wrong, Pony is strongly actor-based, has no shared mutability and permits no unhandled cascading failures, so such an event would very likely be gracefully handled anyway, since even mere indexing requires visible error paths. This nothing-ever-fails aspect to Pony is fairly unique (Haskell and Rust are well known for harsh compilers, but by no means avoid throwing entirely), but it gives a lot more passive safety here. This honestly doesn't seem like a bad choice to me.

Re:1/0 = 0 by semi-extrinsic on Saturday August 11, 2018 @02:32AM (#17738645)
An example well-defined use case is if you want to compute a harmonic mean, e.g.

x = 2/(1/a +1/b)

This is a form of average where you are giving increased importance to the smaller number. It frequently pops up in science/engineering, e.g. in hydrology when you are computing flow of water underground.

In this case, it's "obvious" that when e.g. a is zero, you want 1/a to be zero so you simply return b. There's typically a clear, big distinction between "smallest realistic number", for instance 1e-3, and a zero, whether actual zero or 1e-34.

For instance Numpy offers a nice way of doing this:

  def safeInv(a):
    tol = 1e-16
    return np.division(1.0,a,out=np.zeros_like(a),where=np.where(a>tol))
This tells numpy to put the result of division into an array of zeros shaped like a, but only do the divide where a>tol, so it returns 0 where a<tol.

In this case, though, the programmer understands this division is somehow special and should allow div-by-zero, so it is handled specially.

Re:1/0 = 0 by binarycoffee on Saturday August 11, 2018 @03:46AM (#17738781)
Quite the opposite I would say: the harmonic mean can be seen as a very good justification for `1/0=inf` as the pragmatic choice.

If, say, `a` is mathematically very small (and `x` is accordingly expected very small`) but `a` become zero due to rounding behavior, then having `1/a=inf` results in `x=0` which is arguably closer to the expected result than e.g. `x=2b`.

As someone involved with numerical methods, I have very often relied on `1/0=inf` because it would ultimately warrant the proper behavior in case of rounding errors in the denominator.

Re:1/0 = 0 by Veedrac on Saturday August 11, 2018 @05:47AM (#17739050)
I think for floating point 1/0=Inf makes a lot of sense, because divisions are frequently done with continuously-varying properties. Division by integers is different, since you do a different kind of work with it; there is no "very small" integer.
Re:1/0 = 0 by jibal on Saturday August 11, 2018 @04:17AM (#17738873)
"In this case, it's "obvious" that when e.g. a is zero, you want 1/a to be zero so you simply return b"

b obviously isn't what you want from this harmonic mean when a is 0. And in any case x will be 2b if 1/a is 0, not b.

Re:1/0 = 0 by semi-extrinsic on Saturday August 11, 2018 @10:03AM (#17739709)
So, I did forget the correction such that you don't get 2b. The general case is described e.g. in the link below, and this is known as a "zero-corrected harmonic mean". It is actually "obvious" in some cases, but I'll concede that in other cases it's not.

https://www.rdocumentation.org/packages/lmomco/versions/2.3....

Re:1/0 = 0 by jibal on Sunday August 12, 2018 @03:02AM (#17743299)
Eh? That page says nothing about 1/0 being 0, or anything like that. That function takes the harmonic mean of the non-zero samples, and then adjusts the result by multiplying it by the fraction of the samples that are non-zero. It purposefully avoids dividing by 0. And the result of that function for a==0 and b!=0 is b/2, not b or 2b. So not only is what you claim to be obvious not obvious, it's flat-out wrong.
Re:1/0 = 0 by pps43 on Saturday August 11, 2018 @06:58AM (#17739199)
> `average = 0` with no elements

Imagine a Mars lander program that looks at the average of altitude measurements to decide when it's ok to jettison the parachute, sees no measurements, and decides that altitude is zero.

Re:1/0 = 0 by Veedrac on Saturday August 11, 2018 @07:51AM (#17739325)
You have a point, but I think this is a difference in the target markets. NASA can afford to have a thoroughly-tested, redundant, quickly-accessible failure path that restarts and reinitializes the process, and their processes are so thoroughly tested that they can expect their production instances not to have any software failures.

Pony is made for a more typical scenario where every failure case is a new, untested error path, and history shows that general developers handle errors badly. Pony makes a heroic effort to remove the error path from the language semantics entirely: every failure is explicitly annotated in the code, and has to be handled there. This is much better for the typical developer, allowing them to produce very robust code without NASA's degree of investment towards it. Giving Pony a special unwinding mode just for division by zero would be very dangerous, because this is a new path that only exists for a rarely-encountered sort of error; you cannot assume a sudden shutdown is going to do less damage.

Having Pony present the error cases inline on division by zero would certainly be safer, but there is a degree of disproportionality here: most divisions are impossible to go wrong in this way, and I suspect most of the rest are benign or would be quickly caught by the check after. Since Pony aims to compete against incumbents that are generally less safe in this regard (C++ has UB, Python has exceptions but makes it hard to handle them correctly, etc.), a compromise seems sensible.

Re:1/0 = 0 by pps43 on Saturday August 11, 2018 @08:04AM (#17739364)
It's not only NASA. Zero is just not a reasonable default value for an average. Imagine average credit card balance for FICO score, average blood pressure, average temperature in a freezer, etc.

UB is not the only way. You can have NULLs (they come with their own sets of problems, but still).

In many cases no value is better than incorrect value.

Re:1/0 = 0 by Veedrac on Saturday August 11, 2018 @08:24AM (#17739414)
It's a value type, so you can't really have NULL. I don't see the issue with those examples; if you have no samples, there's nothing to mislabel. An average blood pressure of 0 across 0 patients is only going to harm 0 patients.
Re:1/0 = 0 by pps43 on Saturday August 11, 2018 @08:54AM (#17739489)
> I don't see the issue with those examples

Let me elaborate then.

Average credit card balance predicts probability of default. Joe who maxed out his credit card is higher risk than Jane who pays back her entire credit card balance every month. Now we have Jack with no credit card. We predict that Jack is low risk because his average credit card balance is zero.

Second example, defibrillator that monitors blood pressure and shocks the patient when his heart stops (blood pressure drops to zero). We attach the defibrillator to a patient, turn it on, and it shocks the patient immediately because there are no blood pressure measurements yet and therefore it thinks the average is zero.

Third example, a thermostat that turns on the freezer if average temperature is above a set threshold. It never turns on because average (of zero observations) is already zero.

Of course you can hard-code handling of those special cases, but if you did not, failing would be preferable to continuing to work incorrectly.

Re:1/0 = 0 by seandougall on Saturday August 11, 2018 @01:18PM (#17740569)
It seems to me taking averages would be inappropriate in all three of those scenarios.

Credit risk is based on total debt, and since credit cards are a revolving line of credit, the entire credit limit is considered debt, even if the balance is zero. That's why you can improve your credit score by closing out a credit card that you never use and that carries a zero balance (which we did in order to qualify for a mortgage several years ago). In other words, it's a sum, not an average; there's no division involved.

Setting aside the fact that there are much more reliable ways to detect a stopped heart than blood pressure: If you're taking a running average of BP over time, a low reading after a heart attack would just be a single data point, and you'd probably have to accumulate a bunch of them in order for it to register (particularly if you got a high reading just before the event). Even if you take a reading every five minutes, which is ridiculously frequent for BP, the patient will be long dead by the time you notice. You should be acting based on the last reading; again, no division involved.

I don't see why a freezer would be based on running averages rather than the most recent reading either. Thermostats generally work off of two thresholds: a higher one above which the compressor turns on, and a lower one below which it turns off. That smooths out any measurement noise without taking averages. Even if you do use averages for some reason, though, presumably it will start measuring at _some_ point and the compressor will turn on; I don't see why the average would stay at zero.

I'm not convinced that `1/0 = 0` is correct in any meaningful way, but I feel like any situation where it would cause bugs more critical than a UI issue probably points to a deeper design flaw. After all, if the alternative is to crash on a failed assertion, that's not necessarily preferable in a life-or-death situation.

Re:1/0 = 0 by pps43 on Saturday August 11, 2018 @01:59PM (#17740756)
Everything is relative. $1,000 balance is a lot of money for someone making $35,000, not so much for someone making $350,000. Many independent variables that go into risk scores tend to be ratios or averages, hence zero (or near zero) denominator is possible.

It is normally addressed with floors and ceilings or something like Laplace rule of succession, so that no data at all results in a reasonable number. Very rarely that reasonable number is zero.

I'm not saying taking the average is necessarily good in the examples given, just that if you are computing the average, then that computation should not silently return zero if there's no data to average.

That's the way AVG() in SQL or mean() in R work, they return NULL or NA rather than 0. If you know that NA should be 0 you can explicitly COALESCE, but that should be your decision rather than the default behavior.

Re:1/0 = 0 by Veedrac on Sunday August 12, 2018 @07:54AM (#17743970)
I feel for the typical target market for Pony is going to be doing operations like that in floating point, or perhaps some explicit fixed-point non-integer type in financial cases. Whilst, yes, I can see this causing issues in some small subset of cases, the question really does come down to cost-benefit. Integer division by zero is not the only way for arithmetic to go wrong; would you expect every overflow to be checked too?
Re:1/0 = 0 by labster on Saturday August 11, 2018 @09:24AM (#17739576)
https://en.m.wikipedia.org/wiki/Credit_score_in_the_United_S...

Credit scores don't work this way. Zero is not a valid credit score, and the things you mentioned describe different components of the score.

I work a lot with survey data, to be interpreted by humans. In this problem domain, zero is a sane value for an empty average, though "N/A" is usually better. I wish our language would let us define it as zero so long reports don't die in the middle. But it's about your problem domain, as usual.

Re:1/0 = 0 by pps43 on Saturday August 11, 2018 @12:31PM (#17740324)
There are many different credit scores. The range of valid FICO scores does not include zero, but internal acquisition and behavior scores that banks use might.

But in this case it's irrelevant because average balance is independent variable (input of the scoring model).

Re:1/0 = 0 by jeremyjh on Saturday August 11, 2018 @08:22AM (#17739407)
You can check for 0 and throw in those cases, and then propagate the error path appropriately. And as they've already said in this thread, they will be providing a checked arithmetic in the standard library to do that for you.
Re:1/0 = 0 by Giroflex on Saturday August 11, 2018 @08:31AM (#17739434)
Well, sometimes the average is 0, e.g. (-2 + 2)/2.

And the whole point is that this is meant to catch unforeseen interactions as soon as possible. If you add a check it's no longer unforeseen, and it may easily slip the programmer's mind.

Re:1/0 = 0 by seandougall on Saturday August 11, 2018 @01:19PM (#17740584)
If I'm not mistaken, jeremyjh was referring to checking for 0 in the denominator, not the numerator.
Re:1/0 = 0 by fjsolwmv on Saturday August 11, 2018 @04:56PM (#17741488)
Pony requires programmer to handle everything case of every function...except this one case where it will just pick an arbitrary value to handle a case the progrmammer forgot, hiding the very error Pony was designed to guarantee gets solved. Why not allow partial functions everywhere and have them default to 0 where undefined?
Re:1/0 = 0 by vmchale on Monday August 20, 2018 @01:01AM (#17797821)
That's a terrible default for an average function lol. Once again in nearly all cases, taking the average of a list without elements is an error.
Re:1/0 = 0 by innagadadavida on Friday August 10, 2018 @10:38PM (#17737962)
What happens for 0 / 0? Is this also 0?
Re:1/0 = 0 by taneq on Saturday August 11, 2018 @12:00AM (#17738265)
It's extra zero.
Re:1/0 = 0 by spacehunt on Saturday August 11, 2018 @01:02AM (#17738441)
Is this the same as 0 * 1 / 0?
Re:1/0 = 0 by innocentoldguy on Saturday August 11, 2018 @03:10AM (#17738705)
It returns a larger value of 0.
Re:1/0 = 0 by red_admiral on Saturday August 11, 2018 @06:30AM (#17739147)
All zeroes are equal, but some are more equal than others.
Re:1/0 = 0 by 2038AD on Monday August 13, 2018 @07:27AM (#17749311)
ε
Re:1/0 = 0 by nwmcsween on Saturday August 11, 2018 @12:51AM (#17738411)
inf 0