Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Best way to handle mathematical divide-by-zero case

131 views
Skip to first unread message

JiiPee

unread,
Jan 11, 2017, 1:17:14 PM1/11/17
to
In my interview the interviewer asked me to write a function to
calculate an average value/mean.

And at the end he added: "..and if you divide by zero then you would
maybe throw an exception....". But I have since been thinking is this
the way:


double average(array of values)

{}

Seems like Bjarne recommends not to use exceptions when dividing by zero
but other ways. What would be the best way for the function to report
about "dividing by zero" case? How would you do it?


I kind of agree with Bjarne here.... do you?

Alf P. Steinbach

unread,
Jan 11, 2017, 2:01:06 PM1/11/17
to
I think your question is really three different questions:

• How to report division by zero for floating point calculations.
Easy, that's what NaN is all about.

• How to report division by zero for integer calculations.
Crash.

• How to sensibly deal with an empty set of values for `average`.
More thorny, discussed below.

Consider a multiset S of N numbers. Its average is avg(S) = sum(S)/N.
Now we form the set T = S ⊎ {42}, with N+1 numbers. Its average is
avg(T) = sum(T)/(N+1) = (42 + N*avg(S))/(N+1). A nice update formula.

So what if we want that to work for the case N = 0, i.e. S = {}?

Well, then N*avg(S), i.e. N*avg({}), should better equal 0. And it is 0
no matter which number we choose for avg({}). Unfortunately 0*NaN yields
NaN, but the choice that avg({}) = 0 sounds OK to me.

Another possibility is to return NaN, or to return an empty `Optional`
like `boost::optional` or C++17 `std::optional`. Or one could throw an
exception. Or, one could document the function's contract as requiring a
non-empty set, and then crash/assert on contract violation.

I think the most practically useful behavior would be the 0 return,
documented as such.

But, this opinion could be subject to revision if someone makes a good
case for some other possibility! ;-)


Cheers!,

- Af

JiiPee

unread,
Jan 11, 2017, 2:16:37 PM1/11/17
to
On 11/01/2017 19:00, Alf P. Steinbach wrote:
> I think the most practically useful behavior would be the 0 return,
> documented as such.

But average can also be 0, cant it? So we cannot return 0 (zero) ...

Mr Flibble

unread,
Jan 11, 2017, 4:43:35 PM1/11/17
to
On 11/01/2017 21:42, Stefan Ram wrote:
> r...@zedat.fu-berlin.de (Stefan Ram) writes:
>> the behavior is undefined.
>
> The physicists call »undefined behavior« a "singularity".
>
> The big bang (the time between 0 and some early time)
> was a singularity.
>
> That means we own our existence to undefined behavior.
>
> Blessed are you, undefined behavior.

Word salad.

/Flibble


Wouter van Ooijen

unread,
Jan 11, 2017, 5:21:44 PM1/11/17
to
> ....
> I think the most practically useful behavior would be the 0 return,
> documented as such.
>
> But, this opinion could be subject to revision if someone makes a good
> case for some other possibility! ;-)

I might not agree with 'return 0', but your approach is IMO the only
sound approach: try to find out what makes the most sense for the user.
But alas, that might not be the same for all users...

My approach is often 'let the user decide', which might be done by an
extra lambda/std::function parameter, which gets called in the
divide-by-zero cause. The default could be []{ return 0; }, to match
your case.

For a faster run in the normal cases, but undefined behaviour in the
divide-by-zero case, the caller should have the option to specify []{}
to signify that nothing is to be done, but I don't yet see how that
could be done. (Some template magic will probably help.)

An exception-oriented user could specify []{ throw <something>; }

Wouter "Objects? No Thanks!" van Oijen

JiiPee

unread,
Jan 11, 2017, 7:07:30 PM1/11/17
to
On 11/01/2017 21:28, Stefan Ram wrote:
> #include <interview.h>


haha

JiiPee

unread,
Jan 11, 2017, 7:12:32 PM1/11/17
to
On 11/01/2017 22:54, Stefan Ram wrote:
> r...@zedat.fu-berlin.de (Stefan Ram) writes:
>> double average( const double * a, size_t n );
>> If n is 0, the behavior is undefined.
> Because, what's usually better than
>
> try { ave = average( a, n ); }
> catch( average_of_zero_exception e ) { oops(); }
>
> is
>
> if( n == 0 )oops(); else ave = average( a, n )
>
> .
>

I kind of agree with average(). But with opening-a-file error exception
is better. Somehow it feels strainge to use exception with mathematical
calculations. But yes, my interviewer seemed to like it...Well, i forgot
to mention actually any error handling (which was a mistake obviously).


I kind of agree that in this case its more a documentation issue.
Obviously asserts need to be there for debugging.

David Brown

unread,
Jan 12, 2017, 4:36:30 AM1/12/17
to
Of course you can return 0 if you want.

The average of any empty set is not defined - it simply does not make
sense to take the sum of the values and divide by the number of values
when the set is empty.

So if you are writing a function to calculate an average, you have three
options.

First, you can leave it undefined - it's okay to have "garbage in,
garbage out". Just ignore the possibility. This is a perfectly
reasonable attitude, and it is the most efficient one for both developer
time and run time. But it requires that the function be used correctly,
or behaviour is undefined and may launch nasal daemons, corrupt your
files, or anything else.

Secondly, you can specify the behaviour of the function with empty sets.
Then it is up to you, as the writer of the specification, to say what
you will do when given an empty set. Possibilities include returning 0,
returning NaN, throwing an exception, calling an error handler, popping
up a message, killing the program with an error message. You can even
return 42 if you like - as long as you say what the function will do in
this case, and do it. Usually it is best to do something obvious and
sensible, of course - returning 0 is fine, but returning 42 would look a
bit odd.

Thirdly, you can leave it as unspecified behaviour. Here you say that
the function will return a value of the declared type (double, int,
whatever), without crashing or causing other problems. You just don't
say what number that will be. Typically the implementation will pick a
value (such as 0 or NaN), but you don't specify that value for the function.


This third option is often the best for general use. If someone uses
the function incorrectly (passing an empty set), they have a bug in
their code - but your function implementation is not going to make the
situation worse. The second option may be nicer as an aid to debugging
- it can make it easier for the person who wrote the code to find
possible errors. The first option is fine when there is tight
cooperation between the author of the function, and its user.

JiiPee

unread,
Jan 12, 2017, 8:17:05 AM1/12/17
to
On 12/01/2017 09:36, David Brown wrote:
> On 11/01/17 20:16, JiiPee wrote:
>> On 11/01/2017 19:00, Alf P. Steinbach wrote:
>>> I think the most practically useful behavior would be the 0 return,
>>> documented as such.
>> But average can also be 0, cant it? So we cannot return 0 (zero) ...
> Of course you can return 0 if you want.


If we have a set of numbers: -1, 0 , 1 we have 3 numbers and their
average value/mean is 0. And there was no errors or dividing by zero... :)

JiiPee

unread,
Jan 12, 2017, 8:20:29 AM1/12/17
to
On 12/01/2017 09:36, David Brown wrote:
> Possibilities include returning 0


What do you mean by "returning 0"? Lets says the function header is:

double average(double values[], int count);

So do you mean this functions return value would be 0 if there is an error?

David Brown

unread,
Jan 12, 2017, 9:23:37 AM1/12/17
to
I am perfectly aware that the average of a non-empty set of numbers can
be 0. That does not conflict with 0 being a sensible return value when
the function is called with an empty set. It means that the caller
cannot write:

int x = average(set);
if (x == 0) {
printf("The set was empty\n");
} else {
printf("The average is %i\n, x);
}

But unless the user of the function particularly incompetent, or you
have specifically said the function will handle empty sets in a way that
is suitable here, then the user will never do this. Instead, they will
write:

if (isempty(set)) {
printf("The set was empty\n");
} else {
int x = average(set);
printf("The average is %i\n, x);
}

The reason you make the function return 0 on an empty set is so that
when a user writes this :

int x = average(set);
printf("The average is %i\n, x);

and "set" happens to be empty, then they will get the output "The
average is 0\n", rather than "Launching nasal daemons...\n".




David Brown

unread,
Jan 12, 2017, 9:28:13 AM1/12/17
to
double average(double values[], int count) {
if (count <= 0) return 0;
return std::accumulate(values, values + count, 0.0) / count;
}

It won't return 0 on all errors - such as mismatches between the actual
array size and count. But it will return 0 on an empty set.

JiiPee

unread,
Jan 12, 2017, 10:41:04 AM1/12/17
to
On 12/01/2017 14:28, David Brown wrote:
> double average(double values[], int count) {
> if (count <= 0) return 0;
> return std::accumulate(values, values + count, 0.0) / count;
> }


But this would give a wrong answer if you call this function with:

values[] = {-1,0,1}

isnt it? Because it would return 0 and so the receiver would think there
was some kind of error, right?

But +1 for the std::accumulate! :)

David Brown

unread,
Jan 12, 2017, 10:52:15 AM1/12/17
to
On 12/01/17 16:40, JiiPee wrote:
> On 12/01/2017 14:28, David Brown wrote:
>> double average(double values[], int count) {
>> if (count <= 0) return 0;
>> return std::accumulate(values, values + count, 0.0) / count;
>> }
>
>
> But this would give a wrong answer if you call this function with:
>
> values[] = {-1,0,1}

No, it gives the correct answer - 0.

>
> isnt it? Because it would return 0 and so the receiver would think there
> was some kind of error, right?

No, the receiver would got 0 would only think there is an error if he
did not understand how to use the function properly. And if that is the
case, then returning 0 is just minimising the spread of damage due to
the user's mistake.

The user cannot use a result of 0 to conclude that there was an error
any more than he can use a result of 1 to conclude that the set passed
was { 0, 1, 2 }.

JiiPee

unread,
Jan 12, 2017, 11:13:38 AM1/12/17
to
On 12/01/2017 14:23, David Brown wrote:
> The reason you make the function return 0 on an empty set is so that
> when a user writes this :
>
> int x = average(set);
> printf("The average is %i\n, x);
>
> and "set" happens to be empty, then they will get the output "The
> average is 0\n", rather than "Launching nasal daemons...\n".


I see, so you just want to prevent a crash if all debugging and testing
fails to find that error.

Because an assert() would do the job, but I guess you think debugging
cannot find the errror situation?

JiiPee

unread,
Jan 12, 2017, 11:27:56 AM1/12/17
to
On 12/01/2017 14:23, David Brown wrote:
> The reason you make the function return 0 on an empty set is so that
> when a user writes this :
>
> int x = average(set);
> printf("The average is %i\n, x);
>
> and "set" happens to be empty, then they will get the output "The
> average is 0\n", rather than "Launching nasal daemons...\n".


I see. But in this case I would prefer to use NaN or max_double so the
user would see there is something wrong going on. Because 0 return looks
like a success, but getting max_double would surely be noticed.

David Brown

unread,
Jan 12, 2017, 11:35:46 AM1/12/17
to
It won't necessarily prevent a crash. It will simply provide a
consistent, efficient, and not unreasonable value in the case of an
unreasonable call. In some cases, it might even be considered a useful
part of the specification of the function that the user could rely on
(so that the user does not need to check for empty sets before calling
average).

David Brown

unread,
Jan 12, 2017, 11:38:02 AM1/12/17
to
On 12/01/17 17:27, JiiPee wrote:
> On 12/01/2017 14:23, David Brown wrote:
>> The reason you make the function return 0 on an empty set is so that
>> when a user writes this :
>>
>> int x = average(set);
>> printf("The average is %i\n, x);
>>
>> and "set" happens to be empty, then they will get the output "The
>> average is 0\n", rather than "Launching nasal daemons...\n".
>
>
> I see. But in this case I would prefer to use NaN or max_double so the
> user would see there is something wrong going on.

Feel free - it is your choice.

Personally, I don't like NaNs, and I don't have any use for max_double
because I don't like comparing floating point types for equality (even
though it would work in this case). And I don't like the idea that a
function might fail and return a weird value - to mind mind, functions
never fail, only specifications.

JiiPee

unread,
Jan 12, 2017, 11:44:32 AM1/12/17
to
On 12/01/2017 16:37, David Brown wrote:
> And I don't like the idea that a
> function might fail and return a weird value - to mind mind, functions
> never fail, only specifications.


But the way you use that function, the following situation could happen:

The user read values from a file and gets a zero set and calculates the
average using. The coder forgot to check the zero set (a bug in the
code) so the program prints:

> Average is 0.

But if you return max_double it would print like:

> Avarage is 99999999999999.

which one makes it easier to find that there was a hidden error? :)

The second one, right? So the user of the program can now report this
error and fix. But if the use gets 0, then they think all is fine and
they might try to find the error from other place later on.

JiiPee

unread,
Jan 12, 2017, 11:46:18 AM1/12/17
to
On 12/01/2017 16:44, JiiPee wrote:
>
>
> > Avarage is 99999999999999.
>
> which one makes it easier to find that there was a hidden error? :)
>
> The second one, right? So the user of the program can now report this
> error and fix. But if the use gets 0, then they think all is fine and
> they might try to find the error from other place later on.

So I a little bit agree with C-programmers argument here that "its good
that the program crashes... at least we can find the error then", rather
than a hidden error and then difficult to find where it is. At least
here we know where the error is.


JiiPee

unread,
Jan 12, 2017, 11:48:41 AM1/12/17
to
On 12/01/2017 16:37, David Brown wrote:
> Personally, I don't like NaNs, and I don't have any use for max_double
> because I don't like comparing floating point types for equality (even

We do not need to test for equality... its just that the number is very
strange, so the user will spot the error and thus we can fix the error.

> though it would work in this case). And I don't like the idea that a
> function might fail and return a weird value

But I prefer to get a very weird value that getting a which looks good
but its not. Its like a wolf in sheeps clothing....


Real Troll

unread,
Jan 12, 2017, 11:50:07 AM1/12/17
to

JiiPee

unread,
Jan 12, 2017, 11:51:40 AM1/12/17
to
On 12/01/2017 16:48, JiiPee wrote:
>
>> though it would work in this case). And I don't like the idea that a
>> function might fail and return a weird value
>
> But I prefer to get a very weird value that getting a which looks good
> but its not. Its like a wolf in sheeps clothing....


Somebody reporting the result, if they see: "Average is 0." in a case
there was a zero set, then they have no clue its wrong and they would go
on and report a wrong result. But if that person sees a result: "Average
is 999 exp+395" they surely will not go on and report that, but they
start thinking: "oh, something is wrong here... i ll contact the coder..."

JiiPee

unread,
Jan 12, 2017, 11:53:32 AM1/12/17
to
On 12/01/2017 16:55, Real Troll wrote:
> Try this:
>
> <http://stackoverflow.com/questions/6121623/catching-exception-divide-by-zero>
>
>
> Good luck.


the third answer there says:

"Stroustrup says, in "The Design and Evolution of C++" (Addison Wesley,
1994), "low-level events, such as arithmetic overflows and divide by
zero, are assumed to be handled by a dedicated lower-level mechanism
rather than by exceptions. This enables C++ to match the behaviour of
other languages when it comes to arithmetic. It also avoids the problems
that occur on heavily pipelined architectures where events such as
divide by zero are asynchronous."`"

Mr Flibble

unread,
Jan 12, 2017, 2:10:17 PM1/12/17
to
On 11/01/2017 18:17, JiiPee wrote:
The correct thing to do in C++ is to throw an exception derived from
std::logic_error as dividing by zero is undefined in mathematics and a
bug in code.

/Flibble

Gareth Owen

unread,
Jan 12, 2017, 2:13:07 PM1/12/17
to
Game recognise game

Gareth Owen

unread,
Jan 12, 2017, 2:18:03 PM1/12/17
to
Mr Flibble <flibbleREM...@i42.co.uk> writes:

> The correct thing to do in C++ is to throw an exception derived from
> std::logic_error as dividing by zero is undefined in mathematics and a
> bug in code.

I agree.

My personal choice would be std::invalid_argument or std::domain_error.

David Brown

unread,
Jan 13, 2017, 6:06:23 AM1/13/17
to
In some situations, that might make it easier to spot the problem. In
other situations, it is far worse. Suppose this is code in your
internet-enabled fridge, which is measuring the average amount of coke
you drink so that it can pre-order enough for your expected needs next
month. If you don't drink coke, and it is averaging an empty set, would
you rather your fridge ordered 0 cokes for next month, of 99999999999999
bottles?

If you are writing a general function without knowing /all/ of its
usage, then you do not have any basis for saying that returning
"max_double" is somehow "better" than returning 0. If the user puts in
incorrect data, then your result will /always/ be wrong - no matter what
you return. It is /always/ the function user's responsibility to pass
correct data to a function.

JiiPee

unread,
Jan 13, 2017, 6:36:23 AM1/13/17
to
On 13/01/2017 11:06, David Brown wrote:
> In some situations, that might make it easier to spot the problem. In
> other situations, it is far worse. Suppose this is code in your
> internet-enabled fridge, which is measuring the average amount of coke
> you drink so that it can pre-order enough for your expected needs next
> month. If you don't drink coke, and it is averaging an empty set, would
> you rather your fridge ordered 0 cokes for next month, of 99999999999999
> bottles?

But I would not code it like that. I would do like this:
avCoke = average(..);
if(avCoke > 9999)
something_is_wrong_so_report_about_this();
else
orderCokes();

so i would check that value *before action*. The problem with 0 is that
even if we are checking it it does not raise any concerns as it is a
valid value (zero cokes looks just fine ... but would be wrong here).

This was my whole idea, that we check the value *before doing action*.
So odd values can be identified.

>
> If you are writing a general function without knowing/all/ of its
> usage, then you do not have any basis for saying that returning
> "max_double" is somehow "better" than returning 0.

It might be better in a way that it causes "more mess" so its more
detectable. 0 does not normally cause any doubts (unless a pointer
value). Thats why I chose max-values if I have to chose an error value.
Many C-programmers say the same: "its good that the program crashes so
we can find the error and fix it". In a way it makes sense sometimes.
Its better that the program crashes rather than that it causes damage is
not noticed.

But it also depends on where its used. Obviously if its about cars speed
we might prefer to return 0 rather than make the car go max speed. But
when debugging its easier to find the bug if I get a value 999999999999.

> If the user puts in
> incorrect data, then your result will/always/ be wrong - no matter what
> you return.

but the difference is that with 0 we dont find out that the result was
wrong but with 9999999999 we will more easily see that the result is wrong.

> It is/always/ the function user's responsibility to pass
> correct data to a function.

We are talking here if that fails... so security after that.


David Brown

unread,
Jan 13, 2017, 7:12:55 AM1/13/17
to
On 13/01/17 12:36, JiiPee wrote:
> On 13/01/2017 11:06, David Brown wrote:
>> In some situations, that might make it easier to spot the problem. In
>> other situations, it is far worse. Suppose this is code in your
>> internet-enabled fridge, which is measuring the average amount of coke
>> you drink so that it can pre-order enough for your expected needs next
>> month. If you don't drink coke, and it is averaging an empty set, would
>> you rather your fridge ordered 0 cokes for next month, of 99999999999999
>> bottles?
>
> But I would not code it like that. I would do like this:
> avCoke = average(..);
> if(avCoke > 9999)
> something_is_wrong_so_report_about_this();
> else
> orderCokes();
>
> so i would check that value *before action*. The problem with 0 is that
> even if we are checking it it does not raise any concerns as it is a
> valid value (zero cokes looks just fine ... but would be wrong here).
>
> This was my whole idea, that we check the value *before doing action*.
> So odd values can be identified.

If you check the value /before/ doing action, then you would check the
size of the set before finding the average, and thus write /correct/ code.

What you are asking is for a way to call a function with "garbage in,
garbage out", and somehow distinguish the resulting "garbage out".

And I would far rather that my fridge ordered 99999999999999 bottles of
coke - because the shop would refuse the order and tell me my fridge is
broken. If it ordered 9999 bottles, the shop might just think I was
planning a huge party.

Your example here simply demonstrates that there is /no/ good choice of
a value that you can return that indicates a failure. If you want to
indicate a failure, you need to do it with a /specific/ and /explicit/
mechanism - such as an exception, or returning a <success, value> pair.
If you are willing to accept that the function user's mistake is the
function user's problem, then returning 0 is just as good as any other
value, because /all/ other values could cause problems for badly written
code, just as 0 could.

>
>> It is/always/ the function user's responsibility to pass
>> correct data to a function.
>
> We are talking here if that fails... so security after that.
>

You /cannot/ fix the broken function user's code from within /your/
function. You can somewhat reduce the risk of further damage, and you
can sometimes make it easier to debug the problem, but that is all.
There are times when the /best/ thing to do when detecting bad input is
to crash the program with an error message - and times when that is the
/worst/ think to do.

Please understand this, and stop trying to come up with different return
values and different circumstances. There is /no/ correct answer here.
If people pass invalid input to a function, you cannot give a sensible
result. You may /specify/ a given result for a given input, in which
case that input is no longer valid - but it is again up to the
function's user to understand what the function does.

This has been understood since the beginning of programmable computers
some 200 years ago, and is just as true today:

<https://www.brainyquote.com/quotes/authors/c/charles_babbage.html>
> On two occasions I have been asked, 'Pray, Mr. Babbage, if you put
> into the machine wrong figures, will the right answers come out?' I
> am not able rightly to apprehend the kind of confusion of ideas that
> could provoke such a question.


JiiPee

unread,
Jan 13, 2017, 8:11:39 AM1/13/17
to
On 13/01/2017 12:12, David Brown wrote:
> On 13/01/17 12:36, JiiPee wrote:
>> On 13/01/2017 11:06, David Brown wrote:
>>> In some situations, that might make it easier to spot the problem. In
>>> other situations, it is far worse. Suppose this is code in your
>>> internet-enabled fridge, which is measuring the average amount of coke
>>> you drink so that it can pre-order enough for your expected needs next
>>> month. If you don't drink coke, and it is averaging an empty set, would
>>> you rather your fridge ordered 0 cokes for next month, of 99999999999999
>>> bottles?
>> But I would not code it like that. I would do like this:
>> avCoke = average(..);
>> if(avCoke > 9999)
>> something_is_wrong_so_report_about_this();
>> else
>> orderCokes();
>>
>> so i would check that value *before action*. The problem with 0 is that
>> even if we are checking it it does not raise any concerns as it is a
>> valid value (zero cokes looks just fine ... but would be wrong here).
>>
>> This was my whole idea, that we check the value *before doing action*.
>> So odd values can be identified.
> If you check the value /before/ doing action, then you would check the
> size of the set before finding the average, and thus write /correct/ code.

it depends... Lets think about situation where the user observes values
printed on the screen and acts upon it. In that case we do not have any
checks in the code, but the user checks the values by looking at the
screen. IN this situation average value: 99999999999 printed on the
screen surely would be better than 0, isnt it?

>
> What you are asking is for a way to call a function with "garbage in,
> garbage out", and somehow distinguish the resulting "garbage out".

yes. If the console prints: "999999999999" its easy for the user to spot it.

> And I would far rather that my fridge ordered 99999999999999 bottles of
> coke - because the shop would refuse the order and tell me my fridge is
> broken. If it ordered 9999 bottles, the shop might just think I was
> planning a huge party.

well that was only an example... we can have:
if (> 9999999999)

And no code should be made to order automatically any number of cokes...
of course the program would need to check how many cokes are ordered. OR
course there are many checks that there is a limit how much can be
ordered. No sane program would allow to order 999999999 cokes.

> Your example here simply demonstrates that there is /no/ good choice of
> a value that you can return that indicates a failure.

but if the user sees the value on a screen, 999999999 is easier to spot
than 0, isnt it?

> If you want to
> indicate a failure, you need to do it with a /specific/ and /explicit/
> mechanism - such as an exception, or returning a <success, value> pair.
> If you are willing to accept that the function user's mistake is the
> function user's problem, then returning 0 is just as good as any other
> value, because /all/ other values could cause problems for badly written
> code, just as 0 could.

but in many cases 9999999999999999 is easier to spot than 0, isnt it?
like if the values are printed on the screen (which they are in many
programs).

>
>>> It is/always/ the function user's responsibility to pass
>>> correct data to a function.
>> We are talking here if that fails... so security after that.
>>
> You /cannot/ fix the broken function user's code from within /your/
> function. You can somewhat reduce the risk of further damage, and you
> can sometimes make it easier to debug the problem, but that is all.
> There are times when the /best/ thing to do when detecting bad input is
> to crash the program with an error message - and times when that is the
> /worst/ think to do.
>
> Please understand this, and stop trying to come up with different return
> values and different circumstances. There is /no/ correct answer here.
> If people pass invalid input to a function, you cannot give a sensible
> result.

but even with pointers.... if we cannot put any sensible value, we
normally want to put NULL, because its easier to find that error rather
than put an address which points to an object which does not exist. When
debugging, NULL value is easier to spot than some valid/invalid object
address value.

I dont know, I dont feel like returning 0 in average() if there was an
error, beacause that might confuse to think everything is fine....

David Brown

unread,
Jan 13, 2017, 9:23:41 AM1/13/17
to
On 13/01/17 14:11, JiiPee wrote:

> but even with pointers.... if we cannot put any sensible value, we
> normally want to put NULL, because its easier to find that error rather
> than put an address which points to an object which does not exist. When
> debugging, NULL value is easier to spot than some valid/invalid object
> address value.

Pointers are a little different because they have a specific value that
indicates "does not point to a valid object", i.e., NULL. (Non-null
pointers may also fail to point to valid objects, of course.) It is
also common practice to check for NULL pointers in code - though of
course people may fail to do so.

NaN's are a possible signal type for functions returning a double, but
how often do people check for them? Anyone that is a careful enough
programmer to check that the result of your average function is not an
NaN or infinity, is going to be careful enough to check that they don't
pass invalid data (an empty set) to your function in the first place.
The only real use of NaNs here is if the average function specifically
says it will return NaN on bad input, the high level code is written by
someone who expects intermediary functions to return NaN on errors, and
the middle layer (that calls the average function) is written by a
muppet and never checked by someone who can actually write correct code.

>
> I dont know, I dont feel like returning 0 in average() if there was an
> error, beacause that might confuse to think everything is fine....

Any value you return for a function which received invalid data /will/
be wrong. It does not matter what value you pick - there will be
circumstances in which that value is wrong, and for which that value is
difficult to spot in debugging or testing. It is certainly possible to
pick a return value that is easier for debugging in /some/ cases - but
that value can never be the "best" choice in all cases.

You need to understand that, and accept that - or else you will spend a
great deal of effort trying to do the impossible.

JiiPee

unread,
Jan 13, 2017, 9:58:09 AM1/13/17
to
On 13/01/2017 14:23, David Brown wrote:
> pick a return value that is easier for debugging in/some/ cases - but
> that value can never be the "best" choice in all cases.


sure, if its about "how many time we shoot with a weapon", then 0 is
pretty safe return value rather than 999999999.

Ben Bacarisse

unread,
Jan 13, 2017, 3:25:24 PM1/13/17
to
On the average of no values...

David Brown <david...@hesbynett.no> writes:

> On 12/01/17 17:44, JiiPee wrote:
<snip>
>> But the way you use that function, the following situation could happen:
>>
>> The user read values from a file and gets a zero set and calculates the
>> average using. The coder forgot to check the zero set (a bug in the
>> code) so the program prints:
>>
>>> Average is 0.
>>
>> But if you return max_double it would print like:
>>
>>> Avarage is 99999999999999.
>>
>> which one makes it easier to find that there was a hidden error? :)
>>
>> The second one, right? So the user of the program can now report this
>> error and fix. But if the use gets 0, then they think all is fine and
>> they might try to find the error from other place later on.
>
> In some situations, that might make it easier to spot the problem. In
> other situations, it is far worse. Suppose this is code in your
> internet-enabled fridge, which is measuring the average amount of coke
> you drink so that it can pre-order enough for your expected needs next
> month. If you don't drink coke, and it is averaging an empty set, would
> you rather your fridge ordered 0 cokes for next month, of 99999999999999
> bottles?

The average here would over time (the result being bottles/week or
ml/day or whatever). The zero quantity is on the top of the division.

<snip>
--
Ben.

Chris M. Thomasson

unread,
Jan 13, 2017, 6:34:16 PM1/13/17
to
On 1/11/2017 10:17 AM, JiiPee wrote:
> In my interview the interviewer asked me to write a function to
> calculate an average value/mean.
>
> And at the end he added: "..and if you divide by zero then you would
> maybe throw an exception....". But I have since been thinking is this
> the way:
>
>
> double average(array of values)
>
> {}
>
> Seems like Bjarne recommends not to use exceptions when dividing by zero
> but other ways. What would be the best way for the function to report
> about "dividing by zero" case? How would you do it?
>
>
> I kind of agree with Bjarne here.... do you?
>

FWIW, in my current line of working with floating point divide-by-zero
conditions is that they should be detected _before_ any execution that
would produce the deadly nan, during iteration. So, I check a value v
for zero, if v is zero I make a log in a report and set v to the current
epsilon of the iteration before the divide operation is allowed to be
realized, therefore avoiding divide-by-zero inserting a nan into an
iteration and basically destroying any subsequent iterations.

JiiPee

unread,
Jan 13, 2017, 7:14:41 PM1/13/17
to
On 13/01/2017 23:34, Chris M. Thomasson wrote:
> FWIW, in my current line of working with floating point divide-by-zero
> conditions is that they should be detected _before_ any execution that
> would produce the deadly nan, during iteration.


Another question is that what should happen if somebody forgets to check
that divide by zero before calling average. In your case seems like tha
program crashes?

Chris M. Thomasson

unread,
Jan 13, 2017, 7:56:39 PM1/13/17
to
No crash. However, the div-by-zero cases get detected, logged, and then
epsilon is divided instead of a zero case, and the iteration can
continue on its merry way, without spreading nan's like a damn virus.

The resulting log can be examined, and the renderings wrt replacing
div-by-zero via epsilon can be useful as well.

Chris M. Thomasson

unread,
Jan 13, 2017, 8:35:34 PM1/13/17
to
On 1/13/2017 6:23 AM, David Brown wrote:
> On 13/01/17 14:11, JiiPee wrote:
>
>> but even with pointers.... if we cannot put any sensible value, we
>> normally want to put NULL, because its easier to find that error rather
>> than put an address which points to an object which does not exist. When
>> debugging, NULL value is easier to spot than some valid/invalid object
>> address value.
[...]
> Any value you return for a function which received invalid data /will/
> be wrong.
[...]

What about the "deadlier" case of "kind of" totally wrong? IMVHO, best
to try and "spot/detect" these things before said nasal demons splatter
on proverbial Murphy's law shi% storm rising. A plot with nans tends to
be "easy" to "visually" spot for the rendering tends to resemble the
background color: Damn it!

;^o

Chris M. Thomasson

unread,
Jan 13, 2017, 8:47:00 PM1/13/17
to
A possible rational for replacing zero with "very close to zero" can be:

Well, is was close to zero anyway, and we have a log to see why it got
that close for the iteration in question anyway.

;^)

JiiPee

unread,
Jan 13, 2017, 8:51:27 PM1/13/17
to
On 14/01/2017 00:56, Chris M. Thomasson wrote:
> No crash. However, the div-by-zero cases get detected, logged, and
> then epsilon is divided instead of a zero case, and the iteration can
> continue on its merry way, without spreading nan's like a damn virus.


no I am talking about the situation where you DO NOT check the zero case
but just call that function WITHOUT check. Then it crashes, if the
function does no checks.

Chris M. Thomasson

unread,
Jan 13, 2017, 9:09:38 PM1/13/17
to
Without checking for div-by-zero, and just let it "fly"... Humm...

Well, beware of the infectious nan's that will most likely be cast
throughout subsequent iterations from point crap, of exotic experimental
algorithms in the complex plane. I personally like to be able to log
patient zero, or iteration zero if you will. The infecting agents
point/iteration of origin, so to speak. Nan or infinity, they both
posses the ability to simply ruin/destroy the damn fractal renderings!
Nans, lol, watch this:

https://youtu.be/-EaHLaZbMFs

;^)

Gareth Owen

unread,
Jan 14, 2017, 6:22:02 AM1/14/17
to
"Chris M. Thomasson" <inv...@invalid.invalid> writes:

> FWIW, in my current line of working with floating point divide-by-zero
> conditions is that they should be detected _before_ any execution that
> would produce the deadly nan, during iteration. So, I check a value v
> for zero, if v is zero I make a log in a report and set v to the
> current epsilon of the iteration before the divide operation is
> allowed to be realized

So, instead of getting NaN as answer, you get the wrong answer?
Or is this just for 0./0. (since 1/0. is Inf)?

Of course, if it very much depends on the algorithm you're iterating over

David Brown

unread,
Jan 14, 2017, 12:08:26 PM1/14/17
to
Yes, I know. I was merely trying to give an give an example of why
picking a value to return for bad input is going to be wrong sometimes,
no matter what value you pick. And while max_double or 99999999999999
might be good as an "obviously bad" value in some circumstances, it
might be used with bad results in other circumstances.




Ben Bacarisse

unread,
Jan 14, 2017, 3:31:02 PM1/14/17
to
Then you've lost me. The input in your example is not wrong -- zero
consumption is perfectly normal, quite unlike an average of nothing.

<snip>
--
Ben.

Chris M. Thomasson

unread,
Jan 14, 2017, 3:45:06 PM1/14/17
to
On 1/14/2017 3:21 AM, Gareth Owen wrote:
> "Chris M. Thomasson" <inv...@invalid.invalid> writes:
>
>> FWIW, in my current line of working with floating point divide-by-zero
>> conditions is that they should be detected _before_ any execution that
>> would produce the deadly nan, during iteration. So, I check a value v
>> for zero, if v is zero I make a log in a report and set v to the
>> current epsilon of the iteration before the divide operation is
>> allowed to be realized
>
> So, instead of getting NaN as answer, you get the wrong answer?

In a sense you are correct, however I can review the log and see exactly
how things got to a div-by-zero. This is for rendering pictures, and a
nan or infinity can gum up the works.

> Or is this just for 0./0. (since 1/0. is Inf)?

Therefore, I try to avoid both nan and infinity. I am worried about
passing sqrt a negative number...


> Of course, if it very much depends on the algorithm you're iterating over

The algorithm is computing a Julia set in reverse. Here is some more
information:

https://en.wikipedia.org/wiki/Julia_set#Using_backwards_.28inverse.29_iteration_.28IIM.29

I am also computing the Buddha brot using normal forward iteration on
the roots generated by reverse iteration. Nan aside for a moment, these
iterations can escape into infinity. So, I test to see if it goes off
into never never land before I commit the iteration. If it does I log
it, set z to epsilon in the output structure of the function, and return
it to the caller.

The main problem is that an iteration uses information from previous
iterations. Nans and/or Infinities can propagate throughout the
subsequent iterations, and drastically alter the rendering. Like a virus.

;^o

JiiPee

unread,
Jan 14, 2017, 4:02:35 PM1/14/17
to
On 14/01/2017 20:45, Chris M. Thomasson wrote:
> The main problem is that an iteration uses information from previous
> iterations. Nans and/or Infinities can propagate throughout the
> subsequent iterations, and drastically alter the rendering. Like a virus.


Yes sure 0 is better in most cases as a wrong value. And if its logged
to the file then sure its quite ok, then can see the error.

Chris M. Thomasson

unread,
Jan 14, 2017, 4:03:45 PM1/14/17
to
On 1/14/2017 12:45 PM, Chris M. Thomasson wrote:
> On 1/14/2017 3:21 AM, Gareth Owen wrote:
>> "Chris M. Thomasson" <inv...@invalid.invalid> writes:
>>
>>> FWIW, in my current line of working with floating point divide-by-zero
>>> conditions is that they should be detected _before_ any execution that
>>> would produce the deadly nan, during iteration. So, I check a value v
>>> for zero, if v is zero I make a log in a report and set v to the
>>> current epsilon of the iteration before the divide operation is
>>> allowed to be realized
>>
>> So, instead of getting NaN as answer, you get the wrong answer?
>
> In a sense you are correct, however I can review the log and see exactly
> how things got to a div-by-zero.
[...]
> I am worried about
> passing sqrt a negative number...

Not sure why I was so focused on the div-by-zero case, and sort of mixed
it up with nan and infinities individual cases. Sorry for the confusion
I had to of caused.

;^o

Chris M. Thomasson

unread,
Jan 14, 2017, 4:47:42 PM1/14/17
to
Indeed. Except I set 0 to epsilon. Sometimes, I also try to propagate
the signs of the offending formula and/or value of z, wrt to +-epsilon
for each offense. This is dangerous wrt sqrt, and other nasal demons.

Think of running an unknown formula, and you have to look after the damn
possible moron!

David Brown

unread,
Jan 14, 2017, 6:16:34 PM1/14/17
to
I was not trying to explain how a fridge might figure out your coke
consumption - I was trying to show how returning 99999999999 as an
"obviously wrong" answer when a function is given garbage, is no better
than returning 0. It really doesn't matter what the function is, or
what it does - it's just a function that is unspecified for some inputs.



Ben Bacarisse

unread,
Jan 14, 2017, 7:35:02 PM1/14/17
to
You specified an input for which there is an obviously right answer.
You then asked if one would prefer the right answer or the wrong answer
to be used for ordering coke. That does not illustrate your point
because your point only applies when there is no obviously right answer.

--
Ben.

JiiPee

unread,
Jan 14, 2017, 8:02:05 PM1/14/17
to
It depends on how the function is used. If the function tells a HUMAN
how much coke he needs to order, then surely 999999999 if best answer if
the average() function fails (or gets invalid data in). In this case 0
asnwer would be deceiving and might lead to wrong actions (as the human
WOULD follow it because 0 is normal-sounding number).

so it depends...
but yes, I cannot say 99999999999 is the best return value in ALL
situations. But in many situations I think it is... especially if its
about showing a human what to do and a human is acting according to that
asnwer.

>
>
>

David Brown

unread,
Jan 15, 2017, 10:57:56 AM1/15/17
to
If you are writing a function and you know how it will be used (such as
passing the result onto a human), then there may be a "best" answer for
invalid input. But if you do not know who will use the function, or how
it will be used, then there is /no/ "best return value" for invalid
input. There is not even a "good" or "usually helpful" return value.
Any value you pick will always be bad for some users. Any effort spent
trying to think of a "good return value" is wasted - it is far better to
spend the effort documenting the function better, naming the function
better, or otherwise making it less likely that your function will be
used incorrectly.


JiiPee

unread,
Jan 15, 2017, 12:17:48 PM1/15/17
to
How about that exception-options? You would not throw an exception?

>
>

David Brown

unread,
Jan 15, 2017, 1:13:27 PM1/15/17
to
I don't use exceptions in my programming, but certainly it is not
unreasonable to throw an exception when you get invalid input to the
function.

But we are just going round in circles - this was already mentioned long
ago, along with halting, logging an error message, giving the user an
error box, and any other way of handling errors.

/All/ methods will be bad in some cases. There are /no/ correct ways to
deal with invalid input. Garbage in /always/ gives garbage out. If you
think you can give a "good" error indication, you are wrong. If your
interviewer thinks there is a good solution, he/she is wrong.

The best you can do is make it as obvious as possible how the function
/should/ be used, by documentation or naming. You can also change the
specifications of the function (if you are allowed) - if you /specify/
the function to "return the average of a non-empty set, or 0 for empty
sets" or "return the average of a non-empty set, or throw an EmptySet
exception for empty sets", then there are no invalid inputs, and you can
always give the right answer.

Failing that, you can think about how it is /likely/ that your function
will be used, and find a way to make it easier for users of the function
to quickly find their error. But you will not succeed in finding a
method that works for /all/ users of your function.


And here ends this thread for me. Either you understand the point of
what I have written a dozen times, or you don't.


J. Clarke

unread,
Feb 4, 2017, 7:56:35 AM2/4/17
to
In article <zEudA.1117322$_a3.9...@fx42.am4>,
n...@notvalid.com says...
>
> In my interview the interviewer asked me to write a function to
> calculate an average value/mean.
>
> And at the end he added: "..and if you divide by zero then you would
> maybe throw an exception....". But I have since been thinking is this
> the way:
>
>
> double average(array of values)
>
> {}
>
> Seems like Bjarne recommends not to use exceptions when dividing by zero
> but other ways. What would be the best way for the function to report
> about "dividing by zero" case? How would you do it?
>
>
> I kind of agree with Bjarne here.... do you?

My feeling is that if the interviewer tells you
to throw an exception you throw an effing
exception unless you see a compelling reason not
to.

Jorgen Grahn

unread,
Feb 5, 2017, 5:21:46 AM2/5/17
to
On Wed, 2017-01-11, JiiPee wrote:
> In my interview the interviewer asked me to write a function to
> calculate an average value/mean.
>
> And at the end he added: "..and if you divide by zero then you would
> maybe throw an exception....". But I have since been thinking is this
> the way:
>
>
> double average(array of values)
>
> {}
>
> Seems like Bjarne recommends not to use exceptions when dividing by zero
> but other ways. What would be the best way for the function to report
> about "dividing by zero" case? How would you do it?
>
> I kind of agree with Bjarne here.... do you?

I'd just document that average() has undefined behavior if you feed it
the empty set.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

JiiPee

unread,
Feb 5, 2017, 8:33:12 AM2/5/17
to
On 05/02/2017 10:21, Jorgen Grahn wrote:
> I'd just document that average() has undefined behavior if you feed it
> the empty set.


I had an interview at the central of London. And after i finished the
avarage() function, he asked "thats all?" (I did not mention any error
handling). then he said: "..and maybe to throw an exception ?". So he
seemed to see that a good one..

JiiPee

unread,
Feb 5, 2017, 8:34:18 AM2/5/17
to
On 05/02/2017 10:21, Jorgen Grahn wrote:
> I'd just document that average() has undefined behavior if you feed it
> the empty set.


maybe in a release version, but surely in a debug version an assert()
would be a good there...

Jorgen Grahn

unread,
Feb 5, 2017, 1:51:38 PM2/5/17
to
The documentation would be the same in both cases.

Yes, maybe an assertion ... although the difference between an abort()
and division by zero is slight.

Manfred

unread,
Feb 5, 2017, 7:08:54 PM2/5/17
to
On 01/12/2017 05:27 PM, JiiPee wrote:
> On 12/01/2017 14:23, David Brown wrote:
>> The reason you make the function return 0 on an empty set is so that
>> when a user writes this :
>>
>> int x = average(set);
>> printf("The average is %i\n, x);
>>
>> and "set" happens to be empty, then they will get the output "The
>> average is 0\n", rather than "Launching nasal daemons...\n".
>
>
> I see. But in this case I would prefer to use NaN or max_double so the
> user would see there is something wrong going on. Because 0 return looks
> like a success, but getting max_double would surely be noticed.
>
I believe you got exactly the point here, except that personally I would
not like NaN - INF or max_double even less.
I would indeed go for the exception.

Returning a valid value (0) would likely result in the containing
program to silently give some result which is not correct for the input
data, which in my opinion is a Bad Thing.

Returning NaN would silently allow the program to complete with a NaN
result, which would inform the user that invalid data was provided, but
no more than that.

The exception is indeed meant to provide feedback that invalid data was
provided /and/ what was wrong about it.

The above applies to the average() case, but more in general with
floating point math division by zero can quite often be prevented by
proper rearrangement of expressions and/or taking advantage of INF
processing (NaN remains quite intractable though).
It may be worth noting that the average() calculation is not entirely
floating point math - your denominator is an integer, which by no
coincidence results in the situation to need to be handled as an error.

JiiPee

unread,
Feb 5, 2017, 7:39:24 PM2/5/17
to
On 06/02/2017 00:08, Manfred wrote:
> I would indeed go for the exception.


But Bjarne seems to be against exception in this kind of situation...

Mr Flibble

unread,
Feb 5, 2017, 7:50:41 PM2/5/17
to
And Bjarne isn't always correct. Throwing an exception is entirely
appropriate for handling division by zero which is a BUG.

/Flibble


David Brown

unread,
Feb 5, 2017, 8:02:04 PM2/5/17
to
Bjarne was against making it a standard for C++. You are free to throw
an exception yourself if you want.

But I thought this had already been thrashed to death a few weeks ago -
why are we going through it all again?

JiiPee

unread,
Feb 6, 2017, 2:34:06 AM2/6/17
to
On 05/02/2017 14:26, Stefan Ram wrote:
> template< typename I >
> inline static double narrow_average( I first, I top, size_t size )
> { return ::std::accumulate( first, top, 0.0 )/ size; }


yes should have been something like that. I use for-loop at that time,
but was not so experienced that time.

Manfred

unread,
Feb 6, 2017, 7:56:13 AM2/6/17
to
I don't recall when/where he may have said that, I would be curious;
could you be more specific if you like?

JiiPee

unread,
Feb 6, 2017, 5:25:08 PM2/6/17
to
http://stackoverflow.com/questions/6121623/catching-exception-divide-by-zero

Stroustrup says, in "The Design and Evolution of C++" (Addison Wesley,
1994), "low-level events, such as arithmetic overflows and divide by
zero, are assumed to be handled by a dedicated lower-level mechanism
rather than by exceptions. This enables C++ to match the behaviour of
other languages when it comes to arithmetic. It also avoids the problems
that occur on heavily pipelined architectures where events such as
divide by zero are asynchronous."`

JiiPee

unread,
Feb 6, 2017, 5:26:12 PM2/6/17
to
On 06/02/2017 22:25, JiiPee wrote:
> It also avoids the problems that occur on heavily pipelined
> architectures where events such as divide by zero are asynchronous.


I wonder what does this mean?

Robert Wessel

unread,
Feb 6, 2017, 5:45:49 PM2/6/17
to
There are machines where a divide by zero traps, but the trap is not
precise (not to mention other exceptions). IOW, the divide by zero
does trap, but some undefined number of additional instructions might
get executed before the trap actually happens, plus some *previous*
instructions might not have been executed yet. This is not really an
issue on non- or minimally pipelined machines. OTOH, most mainstream
"large" pipelined CPUs take great pains to preserve the precise nature
of exceptions. That's one of the important things the massive
reordering mechanism at the back end of most x86s does.

So if you rely on the hardware to catch the divide-by-zero on such a
machine, you may not be able to do anything useful after it happens,
since your programs state will be mangled. The alternative is then to
insert a test for zero before every divide, which might be very slow.

Mr Flibble

unread,
Feb 6, 2017, 6:49:21 PM2/6/17
to
You don't have to test before every divide: in this case one simply has
pre-condition check at start of function (empty set throws an exception).

/Flibble


Manfred

unread,
Feb 6, 2017, 6:58:24 PM2/6/17
to
Thanks for the quote.
I may have two comments about this:

1) Appearently Bjarne is referring here to exceptions thrown by the
language itself (or the standard library), and he explains why they
choose not to have the language throw a division-by-zero exception - in
which the argument to match the behaviour of other languages (including
C) is a strong one.
In the average example() I would explicitly throw an exception if the
set is empty, I would not execute the division by zero, or anyway assume
that the division itsels throws an exception.

2) In the general case of floating point arithmetic division by zero
would have some real-valued denominator expression that can evaluate to
zero or any value arbitrarily close to it. In the average() example the
denominator is an integer value, and this is a relevant difference.

As I wrote earlier, when there is a real-valued denominator that can
evaluate to zero or any value close to it, quite often (expecially when
the expression models a physical process) if you happen to have the
expression evaluate to 0/0 (which would yield a NaN) you can in fact
refactor the expression so as to have a well defined form over your
problem domain.
If you happen to get nonzero/0, you may either choose different
variables, or rely on the processor or math library handling of +/-INF
if this suits your problem.
This is to say that with real-valued floating point arithmetic, you have
significant alternatives to handle (or prevent) division by zero before
you treat it as an error condition. Obviously all of this must be
studied in the specifics of the problem at hand.
In my experience division by zero is not the hardest part of floating
point arithmetic. Actually much easier than its finite precision and
rounding errors, which would result e.g. in DBL_EPSILON to be returned
where a zero was expected. This can be much trickier.

JiiPee

unread,
Feb 6, 2017, 7:43:43 PM2/6/17
to
On 06/02/2017 23:58, Manfred wrote:
> In the average example() I would explicitly throw an exception if the
> set is empty, I would not execute the division by zero, or anyway
> assume that the division itsels throws an exception.


what if the average is calculated 10 million times per second? would you
still ldo the check eatch time?

But isnt it this a similar issue to vectors v.at(2) against v[2]?

David Brown

unread,
Feb 7, 2017, 3:22:52 AM2/7/17
to
Do you prefer correct code, or code that is a fraction of a percent
faster but wrong?

It is really quite simple, and I cannot understand why you are taking so
long to get the hang of it.

Let me give you the /one/ rule that actually matters:


* Do not divide by zero - it is a mistake in the code. *


OK?

Now you have that as a rule, you can decide the best way to be sure that
the rule is not broken. That will depend on the circumstances - what
code you have, who is going to call the code, who might make the mistake
of threatening a division by zero, and what you can do about it.
Options include everything from ignoring it (because if some moron calls
your function with an empty set, it is /their/ fault - and you don't
want to slow down the code for competent users), returning fixed values,
throwing an exception, up to automatically sending out an email to the
developers with a deviation report.


The same applies to /all/ other undefined behaviour in the code (such as
accessing an array out of bounds) and all other kinds of errors. Your
target is to avoid them happening. If you think an error /might/
happen, then you find ways to detect the situation and deal with it as
best you can.



Öö Tiib

unread,
Feb 7, 2017, 4:00:48 AM2/7/17
to
On Tuesday, 7 February 2017 02:43:43 UTC+2, JiiPee wrote:
> On 06/02/2017 23:58, Manfred wrote:
> > In the average example() I would explicitly throw an exception if the
> > set is empty, I would not execute the division by zero, or anyway
> > assume that the division itsels throws an exception.
>
> what if the average is calculated 10 million times per second? would you
> still ldo the check eatch time?

Sure. It is dirt cheap compared to everything else involved.
* Do we really have tens of millions of little vectors?
* Why we produce these at such a rate?
* Are we averaging same (smaller set) of vectors over and over again?
* Do we average every vector's contents after every little change to it?
And so on.

Every case imaginable means that we have some design issue that
likely allows us to improve the performance ten times *without*
removing that check. ;)

>
> But isnt it this a similar issue to vectors v.at(2) against v[2]?

The out of bounds index may be received from some dirty
and potentially malicious source (external file, user input,
code of team of your competitor). On rest of the cases out
of bounds index means programming errors. On most of
those cases we likely should not continue whatever we
were doing.

The need to average unexisting values may be normal. For
example readings of some sensor. Checking that we have
received any readings from sensor before we average those
makes perfect sense, continuing to work without those
readings from (one?) sensor may make perfect sense.

Scott Lurndal

unread,
Feb 7, 2017, 8:22:37 AM2/7/17
to
JiiPee <n...@notvalid.com> writes:
>On 06/02/2017 12:56, Manfred wrote:
>> On 2/6/2017 1:39 AM, JiiPee wrote:
>>> On 06/02/2017 00:08, Manfred wrote:
>>>> I would indeed go for the exception.
>>>
>>>
>>> But Bjarne seems to be against exception in this kind of situation...
>>>
>> I don't recall when/where he may have said that, I would be curious;
>> could you be more specific if you like?
>
>http://stackoverflow.com/questions/6121623/catching-exception-divide-by-zero
>
>Stroustrup says, in "The Design and Evolution of C++" (Addison Wesley,
>1994), "low-level events, such as arithmetic overflows and divide by
>zero, are assumed to be handled by a dedicated lower-level mechanism

In particular, hardware detection and SIGFPE generation.


Scott Lurndal

unread,
Feb 7, 2017, 8:24:50 AM2/7/17
to
There were processors architectures in existence where exceptions
were "imprecise", i.e. couldn't be associated with the instruction
that caused the exception. Modern pipelined architectures (x86,
x86_64, arm64) all require precise (synchronous) exceptions for
the most part, but there are still behaviors that are asynchronous
(for example, detection of memory ECC failures on stores).

Ben Bacarisse

unread,
Feb 7, 2017, 9:06:39 AM2/7/17
to
David Brown <david...@hesbynett.no> writes:

> On 07/02/17 01:43, JiiPee wrote:
<snip>
>> what if the average is calculated 10 million times per second? would you
>> still ldo the check eatch time?
<snip>
> It is really quite simple, and I cannot understand why you are taking so
> long to get the hang of it.
>
> Let me give you the /one/ rule that actually matters:
>
> * Do not divide by zero - it is a mistake in the code. *
>
> OK?

I don't think that's a good universal rule. It very often a good rule,
and if you are writing portable C it is an essential rule, but there are
times when you can rely on behaviour outside of the C++ standard. In
those cases writing simpler code and letting IEEE floating point take
care of the NaNs and the Infinities might be the way to go.

<snip>
--
Ben.

Manfred

unread,
Feb 7, 2017, 9:31:42 AM2/7/17
to
On 2/7/2017 1:43 AM, JiiPee wrote:
> On 06/02/2017 23:58, Manfred wrote:
>> In the average example() I would explicitly throw an exception if the
>> set is empty, I would not execute the division by zero, or anyway
>> assume that the division itsels throws an exception.
>
>
> what if the average is calculated 10 million times per second? would you
> still ldo the check eatch time?
Yes, unless in the program by some means it can be guaranteed that the
set can /never/ be empty.
As others have already replied, ensuring a correct result is more
important than saving a few (or many) clock cycles: if you want to save
processing time, you have to do so in such a way that still guarantees
correct results.

>
> But isnt it this a similar issue to vectors v.at(2) against v[2]?
>
It is a different context (out of range is not division by zero). Anyway
for vector elements the designers of the language decided to provide two
access methods, only one of which guarantees range checking. Obviously
this implies that if you want to use the [] form (unchecked) you /need/
to ensure that the vector will /never/ be accessed out of range.
IMHO the rationale for choosing between the two is not speed, it is
whether you can /guarantee/ that out-of-range does not happen. If it is
so, the library gives you a way to save a few machine code instructions.
OTOH, if you cannot guarantee this and still want the [] syntax, Bjarne
gives explicit examples on how to implement a range-checked [] operator.

David Brown

unread,
Feb 7, 2017, 9:59:11 AM2/7/17
to
There is always going to be scope for making things more complicated to
suit particular cases - C and C++ are flexible languages, and compilers
often have a range of options or features that go beyond the bare
requirements of the standards.

However, I think unless you are an expert who is aware of all the
subtleties and has a solid understanding of the target platform(s),
compiler(s) and compiler options, then it /is/ a good rule. And a
poster who wonders if it is okay to skip a check purely on the basis of
the number of times a function is to be called, is not such an expert
(in this particular area).


Actually, I'd go beyond that and keep my rule even for experts -
dividing by zero is a mistake (unless you are dealing with projective
planes and other fun maths). Relying on features such as IEEE floating
point NaNs, infinities, or exceptions is one way of dealing with such
mistakes. Sometimes it is more efficient to do your calculations hoping
there is no problem such as division by zero, with the intention of
detecting the problem afterwards, rather than checking for problems
/before/ doing the calculation. That's fine - but you are not actually
dividing by zero any more. You are doing speculative calculations that
may be aborted by exceptions, or calculations using functions specified
as returning NaN for a denominator of 0 or the quotient otherwise. In
other words, you are using specified, defined behaviour - not the
undefined behaviour of a division by zero.


0 new messages