Assigning the result of a '/' division to an integer type causes rounding

M

Mike S

Does anyone know the logic behind why in VB.NET the result of a
floating-point division ('/') is -rounded- on being converted to an
integer type, such as with statements like

Dim x As Integer = 2/3 'after assignment, x is 1, whereas a sane person
would say it should be 0

Does Microsoft have a reason for this design decision? I understand
that this type of rounding can reduce the overall error in long
computation chains by reducing the amount of error that accumulates
from ignoring the fractional part of intermediate results, but why
specifically does VB.NET do this? It seems very unnatural IMO; I can't
think of any other programming language that does this. It would make
much more sense if VB.NET performed floating-point to integer
conversions by simply dropping everything after the decimal. It makes
even less sense to have to use the integer division ('\') operator when
you need to make it explicit that you -don't- want it to perform
rounding. On that note, I think they got the '/' and '\' syntax
backwards. IMHO...

The '/' operator (what is currently
floating-point-division-with-rounding-on-conversion-to-integer) should
behave similar to how the '/' operator behaves in most other
programming languages: the division should be performed in
floating-point; if the result is then converted to an integer, the
fractional part should simply be thrown out without any rounding.

The '\' operator (so-called "integer division") should do what '/'
currently does in VB.NET. That is, it should perform the division and
then round up if the fractional part is greater than or equal to 0.5.

Think about it. Most programming languages only have one division
operator, which is usually written with '/' by convention. And by
convention, '/' in most programming languages means what '\' (integer
division) means in VB.NET. VB.NET is completely upside-down. Sometimes
I get the feeling that Microsoft intentionally goes out of its way to
avoid following conventions or precedent, or anything that might be
considered 'normal.' ;-)

That's my rant. I'm interested to see what everyone else thinks of all
this, and if anyone indeed knows why Microsoft chose to do division
this way.
 
H

Herfried K. Wagner [MVP]

Mike S said:
Does anyone know the logic behind why in VB.NET the result of a
floating-point division ('/') is -rounded- on being converted to an
integer type, such as with statements like

Dim x As Integer = 2/3 'after assignment, x is 1, whereas a sane person
would say it should be 0

I recommend to turn 'Option Strict' on. The rounding doesn't occur as part
of the division, it's caused by the implicit conversion of the division's
result, which is 0.666..., to 'Integer'. 0.666... is rounded to the
integral number 1 for obvious reasons. With 'Option Strict On' you'll have
to write 'Dim x As Integer = CInt(2 / 3)'.
 
M

Mike S

Herfried said:
I recommend to turn 'Option Strict' on. The rounding doesn't occur as part
of the division, it's caused by the implicit conversion of the division's
result,

Right. I know it's not part of the division. That's why I asked why
does it round the result *on being converted to* an integer type.
which is 0.666..., to 'Integer'. 0.666... is rounded to the
integral number 1 for obvious reasons.

Whether it's "obvious" is a matter of experience, I guess. To me, it
would be obvious if the the conversion caused the fractional part to be
discarded, rather than for the rounding to occur. For example, if you
do this in C++:

#include <iostream>

int main(void)
{
int x = 2/3;
std::cout << x << std::endl;
return 0;
}

The output will be '0'. I think this is the obvious result because, as
I said, most programming languages will do integer conversions by
dropping the fractional part of the answer. The fact that in VB.NET,
the integer conversion causes the answer to be rounded instead is
counter-intuitive if you come from a different language background. My
point is that most, if not all, other programming languages would
convert 0.66666 to integer 0, not 1.
With 'Option Strict On' you'll have
to write 'Dim x As Integer = CInt(2 / 3)'.

That's just a more verbose way to do the same thing as:

Dim x As Integer = 2 / 3
with Option Strict Off (which is the compiler default anyway).

CInt(2 / 3) is still 1. My argument is that CInt(2 / 3) = 0 would be
more logical and by extension implicit integer conversions should also
not round, since an implicit integer conversion should (obviously) be
the same as what an explicit CInt would give.

I'm not hoping to change the VB.NET language specs, I'm simply pointing
out that this is awfully counter-intuitive behavior IMHO...
 
H

Herfried K. Wagner [MVP]

Mike S said:
I'm not hoping to change the VB.NET language specs, I'm simply pointing
out that this is awfully counter-intuitive behavior IMHO...

Well, for somebody like me who is having a strong BASIC background the
behavior seems very intuitive. I don't think that stripping off everything
after the decimal point is more intuitive than rounding when performing the
conversion. Moreover I think that rounding is more "natural" because it
better preserves the actual value. It's simply more high-level.
 
G

GhostInAK

I would have to agree with Herfried. Coming from a strong VB background,
the rounding method is preferred. Also I don't have a huge mathmatics background..
but If on paper I work 2/3 out to be .666666 I naturally round it to 1 if
I need it as an integer. The rounding method is how my brain works naturally,
so I like it.

-Boo
 
D

david

Right. I know it's not part of the division. That's why I asked why
does it round the result *on being converted to* an integer type.

OTOH,

Dim j as Integer = 2
Dim i As Integer = CInt(j/3)

i will now be 0, as most non-VB.Net programmers probably expect, while
CInt(2/3) returns 1.

The moral of the story is to watch out for the CType/CInt/CStr
functions. Visual Basic had lots of features that seem very
counterintuitive for those from other language backgrounds. The
C-functions, and much of the VisualBasic namespace methods, often try to
reproduce this behavior.

Whether you see this behavior as incredibly helpful or incredibly
counterintuitive often depends a lot on your background. I wouldn't say
never use them, but keep in mind that they are Conversion directives NOT
Cast directives, and conversion can mean all kinds of things.

If you don't want the VB-style behavior, stick to directCast and
System.Convert.
 
C

Cor Ligthert [MVP]

Mike,

Did you ever tried this one

\\\
Dim x as Integer = 2\3 'this is the integer divide
///

Cor
 
A

Andrew Morton

david said:
Dim j as Integer = 2
Dim i As Integer = CInt(j/3)

i will now be 0, as most non-VB.Net programmers probably expect, while
CInt(2/3) returns 1.

The latter is evaluated at compile-time, like "abc" & "def" would be
evaluated at compile-time. Blame the compiler, but if you explicitly
want zero, use zero.

Mike said:
The '\' operator (so-called "integer division") should do what '/'
currently does in VB.NET. That is, it should perform the division and
then round up if the fractional part is greater than or equal to 0.5.

Surely it is best that the \ operator behaves in the standard way?
http://mathworld.wolfram.com/IntegerDivision.html
The moral of the story is to watch out for the CType/CInt/CStr
functions

Um, isn't the moral to read the documentation? :)

Andrew
 
D

david

functions

Um, isn't the moral to read the documentation? :)

Well, that's always true, but I don't think anybody really reads the
complete documentation of every single function they call. I'm just
saying that the CType/CInt keywords are a place to be especially careful
about that.

This is especially true since they're billed as Cast Expressions in the
language spec. IMHO, one really doesn't expect a simple cast expression
to do nearly as much work as the CType functions do.
 
G

Guest

remeber there are 3 ways of converting to integers:- Cint, Int, and Fix
pick the one you want!

from the documentation on Cint

<snip>

When you convert a nonintegral value to an integral type, the integer
conversion functions (CByte, CInt, CLng, CSByte, CShort, CUInt, CULng, and
CUShort) remove the fractional part and round the value to the closest
integer.

If the fractional part is exactly 0.5, the integer conversion functions
round it to the nearest even integer. For example, 0.5 rounds to 0, and 1.5
and 2.5 both round to 2. This is sometimes called banker's rounding, and its
purpose is to compensate for a bias that could accumulate when adding many
such numbers together.

CInt and CLng differ from the Int, Fix Functions (Visual Basic), which
truncate, rather than round, the fractional part of a number. Also, Fix and
Int always return a value of the same data type as you pass in.

</snip>
 
G

Guest

guy said:
remeber there are 3 ways of converting to integers:- Cint, Int, and Fix

Int and Fix doesn't convert.

There is also the Math.Round method, that offers more options than Int
and Fix. (It doesn't convert either.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top