8

All experienced programmers in C# (I think this comes from C) are used to cast on of the integers in a division to get the decimal / double / float result instead of the int (the real result truncated).

I'd like to know why is this implemented like this? Is there ANY good reason to truncate the result if both numbers are integer?

Braiam
  • 1
  • 11
  • 47
  • 78
Diego
  • 16,436
  • 26
  • 84
  • 136
  • 6
    That's how integer math works. – Steve Wellens Mar 23 '12 at 14:56
  • 1
    I would say backward compatibility and logical (`int`/`int`=`int` and not `int`/`int`=`double`). Anyone who have used any other programming language would expect this behavior. Are there any other language who do it in any other way? – jgauffin Mar 23 '12 at 14:57
  • [The documentation](http://msdn.microsoft.com/en-us/library/aa691373(v=vs.71).aspx) on this topic is pretty clear. – M.Babcock Mar 23 '12 at 14:58
  • How many full pages would you have, if each page could have 20 items and you have 219 items to fill them with? – Alex In Paris Mar 23 '12 at 14:58
  • 5
    @jgauffin Pascal and Basic have different operators for double and int division, where the type of the result depends on the operator, not on the arguments. – Mr Lister Mar 23 '12 at 15:06
  • If it didn't work that way, the number 1 most used operation after a division would be a truncating conversion.. – harold Mar 23 '12 at 16:00
  • 1
    @jgauffin yes - Pascal (or Delphi at least) implements the result of integer division as a float. It used to really annoy me when I switched to C that the result was a rounded-down integer. After all, at school if you said 3 divided by 2 = 1, your math teacher would not have been impressed! – adelphus Mar 23 '12 at 17:23
  • 1
    @jgauffin, Python 3 gives `int / int = double`. Python 2 worked the other way but now they've added a second operator `//` if you need an integer result. – Mark Ransom Mar 26 '12 at 17:27
  • Methinks it all comes down to efficiency, especially in old times when math coprocessors didn't exist yet. To round, you need a fractional part, i.e. float or double. That would require a conversion, which takes time. In pure integer math, there is never any rounding, it's just not possible without extra code. – Luc VdV Mar 27 '23 at 08:44

6 Answers6

17

C# traces its heritage to C, so the answer to "why is it like this in C#?" is a combination of "why is it like this in C?" and "was there no good reason to change?"

The approach of C is to have a fairly close correspondence between the high-level language and low-level operations. Processors generally implement integer division as returning a quotient and a remainder, both of which are of the same type as the operands.

(So my question would be, "why doesn't integer division in C-like languages return two integers", not "why doesn't it return a floating point value?")

The solution was to provide separate operations for division and remainder, each of which returns an integer. In the context of C, it's not surprising that the result of each of these operations is an integer. This is frequently more accurate than floating-point arithmetic. Consider the example from your comment of 7 / 3. This value cannot be represented by a finite binary number nor by a finite decimal number. In other words, on today's computers, we cannot accurately represent 7 / 3 unless we use integers! The most accurate representation of this fraction is "quotient 2, remainder 1".

So, was there no good reason to change? I can't think of any, and I can think of a few good reasons not to change. None of the other answers has mentioned Visual Basic which (at least through version 6) has two operators for dividing integers: / converts the integers to double, and returns a double, while \ performs normal integer arithmetic.

I learned about the \ operator after struggling to implement a binary search algorithm using floating-point division. It was really painful, and integer division came in like a breath of fresh air. Without it, there was lots of special handling to cover edge cases and off-by-one errors in the first draft of the procedure.

From that experience, I draw the conclusion that having different operators for dividing integers is confusing.

Another alternative would be to have only one integer operation, which always returns a double, and require programmers to truncate it. This means you have to perform two int->double conversions, a truncation and a double->int conversion every time you want integer division. And how many programmers would mistakenly round or floor the result instead of truncating it? It's a more complicated system, and at least as prone to programmer error, and slower.

Finally, in addition to binary search, there are many standard algorithms that employ integer arithmetic. One example is dividing collections of objects into sub-collections of similar size. Another is converting between indices in a 1-d array and coordinates in a 2-d matrix.

As far as I can see, no alternative to "int / int yields int" survives a cost-benefit analysis in terms of language usability, so there's no reason to change the behavior inherited from C.

In conclusion:

  • Integer division is frequently useful in many standard algorithms.
  • When the floating-point division of integers is needed, it may be invoked explicitly with a simple, short, and clear cast: (double)a / b rather than a / b
  • Other alternatives introduce more complication both the programmer and more clock cycles for the processor.
phoog
  • 42,068
  • 6
  • 79
  • 117
  • OMG! Excelent asnwer! Thanks for all the information! I still have one question: If the CPU returns a division as two integers, each time I make a division I'm "waisting" CPU time? – Diego Mar 27 '12 at 00:49
  • Just as a side note: "why doesn't integer division in C-like languages return two integers". Interestingly, x86 processors *do* calculate both the quotient and the remainder when performing an integer division instruction. Unfortunately, the C-like language syntax does not allow both parts to be natively returned in one statement. – adelphus Mar 27 '12 at 09:24
  • @adelphus that's what I intended to convey when I wrote "Processors generally implement integer division as returning a quotient and a remainder, both of which are of the same type as the operands." – phoog Mar 27 '12 at 13:25
  • @Diego yes! The amount of time wasted is vanishingly small, however. In an application where this had a measurable impact on performance, you could write something in machine code, if you were unable to find a compiler that would capitalize on the quotient-remainder result of the machine instruction. – phoog Mar 27 '12 at 13:31
  • That would be the `div` function in `math.h`. – Mr Lister Mar 27 '12 at 14:34
  • @MrLister which is not particularly helpful in C#. There's a DivRem function in System.Math, but the jitter seems to perform the division twice to get the result, at least on x86. – phoog Mar 27 '12 at 14:37
12

Is there ANY good reason to truncate the result if both numbers are integer?

Of course; I can think of a dozen such scenarios easily. For example: you have a large image, and a thumbnail version of the image which is 10 times smaller in both dimensions. When the user clicks on a point in the large image, you wish to identify the corresponding pixel in the scaled-down image. Clearly to do so, you divide both the x and y coordinates by 10. Why would you want to get a result in decimal? The corresponding coordinates are going to be integer coordinates in the thumbnail bitmap.

Doubles are great for physics calculations and decimals are great for financial calculations, but almost all the work I do with computers that does any math at all does it entirely in integers. I don't want to be constantly having to convert doubles or decimals back to integers just because I did some division. If you are solving physics or financial problems then why are you using integers in the first place? Use nothing but doubles or decimals. Use integers to solve finite mathematics problems.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • I don't think that each scenario where you would truncate if division wouldn't is a good reason.. there are also lots of scenarios where you don't want. And I don't think it is wrong (or odd) to have two integers and want to divide them and not truncate, so why (if I know they are integers) should I use double or decimal? – Diego Mar 23 '12 at 16:20
  • @Diego - I think that the point is, there are many situations where you don't want fractional results. There are, of course, also situations where you do want fractional results. Thus, no matter whether division returns an integer or a floating point value, you will not satisfy all use cases. – kvb Mar 23 '12 at 16:58
  • Yes, of course, but I my point is: why decide which satisfy by amount and not by the approach more correct? I still think 7 / 3 is 2.33... and not 2. – Diego Mar 23 '12 at 17:00
  • @Diego - The problem is that you are thinking in human math terms, wheras the computer "thinks" in the terms dictated by the language. You were asking specifically about C#, where the language designers decided to use integer division for people who are coming from C/C++ and Java and the designers were trying to accomodate their way of thinking from those languages. As for the reasons for why in the previous languages the dicision was made, you got many answers basically telling you the same answer. [cont] – Attila Mar 23 '12 at 17:18
  • @Diego - [cont] It is perfectly valid to design a language where you have just "number" and no "integer" or "float" and the mathematical operations are performed according to the proper human math rules. C/C++, Java, C# and the like were not designed this way. – Attila Mar 23 '12 at 17:21
  • 3
    @Diego - First of all, there are historical and performance reasons that affect the decision, as Attila and others have noted. However, I think that you're ignoring that in the real world there are many times when the fractional answer doesn't make sense. Eric gave one example, but there are plenty of others. If I have a classroom of 23 children and I want to break them into 10 groups for some activity, in what sense is it "more correct" to say that each group should have 2.3 children? – kvb Mar 23 '12 at 19:30
10

Calculating on integers is faster (usually) than on floating point values. Besides, all other integer/integer operations (+, -, *) return an integer.

EDIT: As per the request of the OP, here's some addition:

The OP's problem is that they think of / as division in the mathematical sense, and the / operator in the language performs some other operation (which is not the math. division). By this logic they should question the validity of all other operations (+, -, *) as well, since those have special overflow rules, which is not the same as would be expected from their math counterparts. If this is bothersome for someone, they should find another language where the operations perform as expected by the person.

As for the claim on perfomance difference in favor of integer values: When I wrote the answer I only had "folk" knowledge and "intuition" to back up the claim (hece my "usually" disclaimer). Indeed as Gabe pointed out, there are platforms where this does not hold. On the other hand I found this link (point 12) that shows mixed performances on an Intel platform (the language used is Java, though).

The takeaway should be that with performance many claims and intuition are unsubstantiated until measured and found true.

Attila
  • 28,265
  • 3
  • 46
  • 55
  • @Diego: I think it's a very good reason. All operations on a particular type should, *usually*, return a result of the same type. Otherwise it would be terribly confusing. [Edit: Diego removed his comment - we was suggesting that dividing ints returning an int wasn't a good reason] – Matt Burland Mar 23 '12 at 14:58
  • 1
    +1. If it were to return anything but an `int`, it would no longer be integer math! This is how it works with all types: the result of a `uint` division is a `uint`, the result of a `float` division is a `float`, etc. In the absense of any cast, how should the calculation be done, as `float`, `double` or `decimal`? The compiler would have to choose. If you want one of those results, you choose. – Mr Lister Mar 23 '12 at 14:59
  • Division between integers is not necessarily faster than division between floats. – Gabe Mar 23 '12 at 15:41
  • If @Gabe's comment is right then the first argument is invalid. Now with the second: `positive + positive` is positive, also the product or the division, so great! lets make `positive - positive` always be positive.. right? – Diego Mar 23 '12 at 16:23
  • 1
    @Gabe - AFAIK unless you have special hardware, you can safely assume that integer operations are faster than the corresponding floating point ones. – Attila Mar 23 '12 at 17:23
  • @Attila: On architectures like the Alpha that have FP divide hardware but no integer divide, the integer divide has to be implemented in terms of FP calls, necessarily making it slower. You'll probably find this in architectures like GPUs also. – Gabe Mar 23 '12 at 17:31
  • 1
    @MrLister the problem is that `/` is frequently called division, when it's not. 3 divided by 2 equals 1.5: everyone knows this, yet developers are so used to integer math that it doesn't register that the / operator does not match the mathematic correctness of the other operators. – adelphus Mar 23 '12 at 17:34
  • @Diego Why ask the question if you're not prepared to accept the answer? You asked why an integer division is integer; various people gave you the answer; but still you go on saying that it's wrong. Well then, I've got one recommendation: Delphi. There. Oh, and you're right about the positive types (they're called `uint` in C#, by the way); `uint-uint` is `uint`, so you'll never end up with a negative number, even if the second argument is larger than the first. Can you live with that? – Mr Lister Mar 23 '12 at 18:00
  • @Mr Lister. It's not about being prepared to accept the answer. I just don't think that any of the answer are really answering the question (which is a good reason). On of the two arguments of this question is being refuted by @Gabe (I don't really know enough to understand which is the right one). And the other doesn't seem really a good reason, is is more like a excuse. @adelphus: I think your comment here would make an excellent answer! `/` just is not division. – Diego Mar 23 '12 at 18:37
  • @Diego - If your problem is that you think of `/` as division in the mathematical sense, and the `/`operator in the language performs some other operation (which is not the math. division), then you should just as well question the validity of all other operations (`+`, `-`, `*`), since they have special overflow rules, which is _not_ the same as you would expect from their math counterparts. If this is the case, maybe you should find another language where these operations perform as _you_ would expect. – Attila Mar 23 '12 at 18:58
  • @Attila, maybe I really should find some other language. Would you please add to your answer what you've just said here to complete it? Also if you have any links where the performance issue is explain or at least shown I'd really appreciate it. – Diego Mar 23 '12 at 19:50
2

Yes, if the end result needs to be a whole number. It would depend on the requirements.

If these are indeed your requirements, then you would not want to store a decimal and then truncate it. You would be wasting memory and processing time to accomplish something that is already built-in functionality.

Justin Pihony
  • 66,056
  • 18
  • 147
  • 180
  • I don't think I understand.. why to change the result of the division. If you need to truncate, save the decimal result and then truncate (or round or whatever). – Diego Mar 23 '12 at 14:55
  • But, why waste the memory and processing. I will update my answer – Justin Pihony Mar 23 '12 at 14:57
2

The operator is designed to return the same type as it's input.

Edit (comment response): Why? I don't design languages, but I would assume most of the time you will be sticking with the data types you started with and in the remaining instance, what criteria would you use to automatically assume which type the user wants? Would you automatically expect a string when you need it? (sincerity intended)

John MacIntyre
  • 12,910
  • 13
  • 67
  • 106
1

If you add an int to an int, you expect to get an int. If you subtract an int from an int, you expect to get an int. If you multiple an int by an int, you expect to get an int. So why would you not expect an int result if you divide an int by an int? And if you expect an int, then you will have to truncate.

If you don't want that, then you need to cast your ints to something else first.

Edit: I'd also note that if you really want to understand why this is, then you should start looking into how binary math works and how it is implemented in an electronic circuit. It's certainly not necessary to understand it in detail, but having a quick overview of it would really help you understand how the low-level details of the hardware filter through to the details of high-level languages.

Matt Burland
  • 44,552
  • 18
  • 99
  • 171