News for hackers. Stuff that matters.
Re:1/0 = 0 by bunderbunder on Friday August 10, 2018 @05:06PM (#17736728)
I almost want two different division operations: One where 1/0 = 0, exclusively for use in progress bars and stuff like that, and another one for everything else.

Because frequently division by zero indicates a bug. But similarly frequently, I end up crapping out annoying little bits of code like

  if (foo == 0):
    return 0
  else:
    return bar / foo
Re:1/0 = 0 by simias on Friday August 10, 2018 @05:57PM (#17737016)
I'm reading the "Pony" tweet quoted in TFA and your comment and I'm left very puzzled: is that really that common to want x / 0 == 0 ? In practice where does that crop up?

You say that you frequently have to write your little shim but honestly I don't remember writing code like that in recent memory.

You talk about progress bars, I suppose it makes sense if you somehow try to copy 0 elements for instance, and you end up dividing by zero when computing the progress, like:

    pos_percent = (copied_elems * 100) / total_elems
And both copied_elems and total_elems are zero. But in this case wouldn't you want the computation to return 100% instead of zero?

It's also a bit odd because it introduces a discontinuity: as the divisor goes towards zero the result of the operation gets greater until it reaches exactly zero and it yields 0. Wouldn't it make more sense to return INT_MAX (for integers) or +inf for floats? If you're writing a game for instance it might work better.

I guess it just goes to show that it probably makes a lot of sense to leave it undefined and let people write their own wrapper if necessary to do what works best for them in their given scenario.

Re:1/0 = 0 by huehehue on Friday August 10, 2018 @06:40PM (#17737210)
Practically, it's quite common to not immediately know the divisor. In cases where the divisor is initially unknown but takes an imperceptible amount of time to compute it's better to render 0%. Otherwise you might get a flash of a full progress bar (for example) while the divisor is determined.

Of course, it's context dependent. As others mention, your code might be full of stuff like X / (divisor || 1).

Re:1/0 = 0 by adrianratnapala on Friday August 10, 2018 @07:11PM (#17737349)
The nicest UX would be to say something like "waiting..." while the denominator is zero. Presenting a zero to the user instead is probably an acceptable short-cut, but at the end of the day, it's a UX decision. Which is why it should be handled in explicit if-else code, that lives as close to the UI as possible, rather than being buried in the semantics of basic numerical operators.
Re:1/0 = 0 by Too on Saturday August 11, 2018 @01:14AM (#17738467)
If you dont know the number of elements, shouldnt that be tracked in another variable, instead of reusing the total elements variable and assuming 0 elements means unknown?

Also, if loading total elements takes a significant amount of time, shouldnt this loading also be reflected in the progess bar?

Re:1/0 = 0 by octalmage on Friday August 10, 2018 @06:57PM (#17737296)
I’ve run into this a bit with progress related stuff. I bet if you looked at progress bar libraries they’d have similar logic built in.
Re:1/0 = 0 by user5994461 on Friday August 10, 2018 @07:45PM (#17737481)

    X / (divisor || 1).
It's invalid code in C, C++ and Java.
Re:1/0 = 0 by l_t on Friday August 10, 2018 @07:54PM (#17737514)
Boolean operators returning values is common, especially in dynamically typed languages. The code is valid in JavaScript, for example, and in Python (except it uses "or" instead of "||").
Re:1/0 = 0 by user5994461 on Friday August 10, 2018 @08:24PM (#17737607)
In python, it should probably be corrected with // or 1.0 to make it either an integer division or a float division.
Re:1/0 = 0 by l_t on Friday August 10, 2018 @08:45PM (#17737667)
Ah, that's true. Good point.
Re:1/0 = 0 by bqe on Friday August 10, 2018 @09:43PM (#17737841)
This is valid C and C++.
Re:1/0 = 0 by cyphar on Friday August 10, 2018 @09:48PM (#17737855)
It is, but it will always give you a divisor of 1 (because "true" is 1 -- I also thought it would work until I tested it):

    % cat >division.c <<EOF
    #include <stdio.h>
    
    int main(void)
    {
            printf("1/0 = %d\n", 1 / (0 || 1));
            printf("1/2 = %d\n", 1 / (2 || 1));
    
            printf("1.0/0 = %f\n", 1.0 / (0 || 1));
            printf("1.0/2 = %f\n", 1.0 / (2 || 1));
    }
    % gcc -Wall -o divison divison.c
    % ./divison
    1/0 = 1
    1/2 = 1
    1.0/0 = 1.000000
    1.0/2 = 1.000000
In Python this is not the case:

    % python3
    >>> 1 / (0 or 1)
    1
    >>> 1. / (0 or 1)
    1.0
    >>> 1 / (0 or 1)
    1
    >>> 1. / (2 or 1)
    0.5
    % python3
    >>> 1 / (0 or 1)
    1.0
    >>> 1 / (2 or 1)
    0.5
Re:1/0 = 0 by comex on Saturday August 11, 2018 @06:12AM (#17739111)
Some trivia: GNU extensions to C/C++ include a "?:" operator that does what you'd want in this case, e.g.

    x / (divisor ?: 1)
Re:1/0 = 0 by user5994461 on Saturday August 11, 2018 @06:09AM (#17739103)
It shouldn't be valid in C++. booleans cannot participate in arithmetic operations. You will get a warning from the compiler if you are lucky.

C doesn't have booleans and treat them as integers 0 or 1, it can do the math and will always return 1.

Re:1/0 = 0 by comex on Saturday August 11, 2018 @06:16AM (#17739117)
That's not true. C++ does define an implicit conversion from bool to int:

https://en.cppreference.com/w/cpp/language/implicit_conversi... (under "Integral promotion")

And C has a boolean type as of C99.

Re:1/0 = 0 by int0x80 on Friday August 10, 2018 @11:05PM (#17738049)
What do you expect for that C code?
Re:1/0 = 0 by cyphar on Saturday August 11, 2018 @11:41AM (#17740103)
In the context of this discussion, the idea was that it would act the same way as Python. But it obviously doesn't.
Re:1/0 = 0 by nostrademons on Friday August 10, 2018 @06:56PM (#17737293)
Real example: I'm collecting some quality signals from a corpus, most of which are some form of ratio, average, weighted average, or scaled average of counting various quantities within the documents. If the elements being counted are missing, I want the term involving that quality signal to disappear from the final ranking calculation.

Defining x / 0 = 0 gets this behavior for free, while leaving zero as an exception means it has to be caught for every single signal calculation, which is a pain when there are potentially dozens of different signals, all of which are counting different things (and have different divisors). I've actually defined a helper function to do this automatically, which also lets me change the default "null object" easily if I choose a different representation or want to apply some baseline value.

Re:1/0 = 0 by goerz on Saturday August 11, 2018 @01:26AM (#17738496)
Defining a function would seem like exactly the right thing to do! There's no problem.
Re:1/0 = 0 by nostrademons on Saturday August 11, 2018 @03:57AM (#17738820)
Module-scoped operator overloading would be really, really nice in this situation, though.
Re:1/0 = 0 by vmchale on Monday August 20, 2018 @01:23AM (#17797881)
No, it probably wouldn't, unless you were using integers. Pony still uses floats and returns NaN or Infinity or something.
Re:1/0 = 0 by ummonk on Saturday August 11, 2018 @02:06AM (#17738592)
>It's also a bit odd because it introduces a discontinuity: as the divisor goes towards zero the result of the operation gets greater until it reaches exactly zero and it yields 0. Wouldn't it make more sense to return INT_MAX (for integers) or +inf for floats?

Unless you're using unsigned ints, the discontuity will exist no matter what you do, because of negative divisors.

Re:1/0 = 0 by arcticbull on Friday August 10, 2018 @09:34PM (#17737818)
Rust has your back:

pub fn checked_div(self, rhs: u8) -> Option<u8>

Checked integer division. Computes self / rhs, returning None if rhs == 0.

You would use this as lhs.checked_div(rhs).unwrap_or(your sane default)

This is dramatically better than always returning zero silently, as doing so is bound to be wrong in certain cases. If you run into a situation where you are afraid your RHS may be 0 but still want to do the right thing, this is what you'd use.

Re:1/0 = 0 by azernik on Friday August 10, 2018 @05:38PM (#17736930)
This is actually included in the IEEE754 floating point standard - there's a concept of "trapping" vs. "non-trapping" exceptions, where implementations are allowed to decide which exceptions should trap.

Unfortunately, GCC only lets you enable this globally (within a program): see http://www.gnu.org/software/libc/manual/html_node/FP-Excepti....

Re:1/0 = 0 by spooneybarger on Friday August 10, 2018 @05:20PM (#17736833)
We will be introducing two sets of integer math operators in Pony. The current which are non-partial and can over/underflow + division by zero == 0 AND new ones that will be partial functions that cause an error on under/overflow and division by zero.
Re:1/0 = 0 by gopalv on Friday August 10, 2018 @05:37PM (#17736922)
> new ones that will be partial functions that cause an error on under/overflow and division by zero.

A "strict" mode is usually always an afterthought once we have errors & people run it in strict mode and facepalm.

One of the first "utilities" I wrote for PHP was something called "pecl/scream", which turned off all the "unchecked" operations across the whole VM.

And in general, this works out poorly for code quality.

Re:1/0 = 0 by jeremyjh on Friday August 10, 2018 @06:19PM (#17737117)
There is no golden path here. Checked exceptions for division would make a lot of Pony code objectively worse. Unchecked exceptions are great for PHP, Haskell, Rust or Go, but Pony is trying to do something different - to literally make it impossible to panic in an operation without describing that in the type system. The ergonomics of divide by zero in this context are absolutely debatable, not an issue to dismiss out-of-hand.
Re:1/0 = 0 by garmaine on Friday August 10, 2018 @06:46PM (#17737241)
Well, except for kernel panics and hardware errors...
Re:1/0 = 0 by jeremyjh on Friday August 10, 2018 @06:53PM (#17737281)
You can write user code in Pony that will cause a kernel panic or hardware error?
Re:1/0 = 0 by spooneybarger on Friday August 10, 2018 @07:06PM (#17737328)
Yes. Hardware errors, can't really protect from that or a kernel panic. A kernel panic is a panic in non-pony code.
Re:1/0 = 0 by mpolsz on Saturday August 11, 2018 @02:18AM (#17738619)
> You can write user code in Pony that will cause a kernel panic or hardware error?

You can always (as in OS with lazy allocation) allocate enough memory to get OOM no matter how safe your language is.

Re:1/0 = 0 by garmaine on Friday August 10, 2018 @08:27PM (#17737614)
It may be forced to error as a result of one.
Re:1/0 = 0 by rhencke on Friday August 10, 2018 @06:17PM (#17737109)
Pony is not 1.0 yet. The language is still malleable.
Re:1/0 = 0 by ghayes on Friday August 10, 2018 @07:05PM (#17737325)
Couldn’t you alternatively introduce total operators that just grow the memory size as necessary instead of overflowing? For me if you’re handling wrapped types, I’d always prefer the numbers to grow into extra memory instead of overflowing or raising exceptions. Erlang, for instance, does this well. Obviously, division may still not be total, though you could define an operator like `//` that is.
Re:1/0 = 0 by spooneybarger on Friday August 10, 2018 @07:14PM (#17737360)
A wrapped types library with the corresponding performance tradeoff is something I expect will be added to Pony at some point. There's definitely value in them for a variety of use cases.
Re:1/0 = 0 by smallnamespace on Friday August 10, 2018 @06:34PM (#17737176)
Isn't a ternary here nicer?

  return (foo == 0) ? 0 : bar / foo
or even

  return bar / max(1, foo)
in the case where foo is integer or tiny foo would overflow your range anyway
Re:1/0 = 0 by KennyCason on Friday August 10, 2018 @06:53PM (#17737276)
I would say it doesn't really matter much as both are readable. I would prefer either the original if/else or the ternary solution over the last solution as I personally think the intent is not as immediately clear in your "max" form. I would optimize for readability over density, unless there is some reason to write it differently (e.g. performance).

just for fun, in kotlin (making use of expressions removes some verbosity):

    return where(den) { 
       0 -> 0 
       else -> num / den 
    }

    return if (den == 0) { 0 }  
           else { num / den }
Re:1/0 = 0 by Dylan16807 on Friday August 10, 2018 @07:30PM (#17737429)
Ternary doesn't really look any better. I'd do this in a language that supports it though:

  return foo && bar / foo
Re:1/0 = 0 by mehrdadn on Friday August 10, 2018 @07:27PM (#17737414)
I've run into this a lot, but I'm also not sure what I really want to happen. Even for progress bars, the behavior can be different depending on how exactly you're obtaining the denominator -- does it increase dynamically or is it known from the beginning? Is it one of those fake progress bars that just ignores the fact that it'll stay at 100% for the next hour, or would it filling up genuinely mean that the work is actually done? After all, if you have 0 operations total and you've finished 0 of them, are you really 0% done? Wouldn't it make more sense to say you're 100% done? At the end of the day the user is trying to figure out how long they should keep waiting, to which the answer would be "you don't need to wait, there's no more work left to do".
Re:1/0 = 0 by alexkavon on Friday August 10, 2018 @05:20PM (#17736835)
> But similarly frequently, I end up crapping out annoying little bits of code

Isn't this reason the the point of having a utils library with commonly used pieces of code?

Re:1/0 = 0 by dmix on Friday August 10, 2018 @05:52PM (#17736991)
Some utilities libraries can be reflections of deficiencies in the language itself and not simply about common code reuse.
Re:1/0 = 0 by alexkavon on Friday August 10, 2018 @10:27PM (#17737940)
Agreed. Both really.
Re:1/0 = 0 by ifdefdebug on Friday August 10, 2018 @09:53PM (#17737866)
Most of the time when I have to think about what to do with a 0 divisor, I come to the conclusion that

  if (foo == 0):
    return MAX_FLOAT
  else:
    return bar / foo
is more sound for the given algorithm than "return 0" (still crappy, but more sound).

Then use MAX_FLOAT as an error flag instead of 0, which could have been the result of a legal operation (with bar==0).

Re:1/0 = 0 by bluecalm on Saturday August 11, 2018 @09:53AM (#17739658)
Wait, when creating a progress Duke you divide in other direction: (things already done) / (all things). Can you give a specific example when it causes problems? My experience of writing code like that is that there a clearer way or I made a mistake somewhere.
Re:1/0 = 0 by ian1321 on Saturday August 11, 2018 @02:45PM (#17740983)
Honest question. What is so annoying about that code? It's handling (in an application-specific manner) the special case of dividing by zero (which the `/` operator doesn't handle). I'm not sure of any other way to handle this.
Re:1/0 = 0 by xxbgbqbq on Friday August 10, 2018 @07:15PM (#17737361)
Actually, bar/foo STILL has a gotcha which can throw exception, many developers doesn't think of this.

Just try INT_MIN/-1, can blow most "foolproof" divide logic away.