www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - integer division with float result

reply Stas Sergeev <stsp aknet.ru> writes:
Hi.

This is basically an out of curiosity.
I wonder how does D handle the integer division.
In C, as we all know, the following:
int a = 3;
int b = 5;
float c = a / b;
will give the result that will beat the ghost
out of any mathematician (unless you cast
one of the operands to float, of course).
I haven't used D yet, but I know that most
(or all?) of the C-unrelated languages do
that in a proper way, and even the Python
developers are going to fix that in the future.

So the question is: how does D handle that?
Was it infected by the Cish way of handling
an integer division (if so - why?), or managed
to get rid of that legacy thingy?
Nov 18 2007
next sibling parent Jason House <jason.james.house gmail.com> writes:
Stas Sergeev wrote:

 Hi.
 
 This is basically an out of curiosity.
 I wonder how does D handle the integer division.
 In C, as we all know, the following:
 int a = 3;
 int b = 5;
 float c = a / b;
 will give the result that will beat the ghost
 out of any mathematician (unless you cast
 one of the operands to float, of course).

Curiously enough, I hit this very bug rather recently with D 1.x code. I'm ashamed to say that I hit it twice.
 So the question is: how does D handle that?

It silent does what I suspect you fear it would do.
Nov 18 2007
prev sibling next sibling parent reply Lars Noschinski <lars-2006-1 usenet.noschinski.de> writes:
* Stas Sergeev <stsp aknet.ru> [07-11-18 22:10]:
I haven't used D yet, but I know that most
(or all?) of the C-unrelated languages do
that in a proper way, and even the Python
developers are going to fix that in the future.

Which languages do that (without having a separate operator for integer division)?
Nov 18 2007
parent Derek Parnell <derek nomail.afraid.org> writes:
On Sun, 18 Nov 2007 23:40:52 +0000 (UTC), Lars Noschinski wrote:

 * Stas Sergeev <stsp aknet.ru> [07-11-18 22:10]:
I haven't used D yet, but I know that most
(or all?) of the C-unrelated languages do
that in a proper way, and even the Python
developers are going to fix that in the future.

Which languages do that (without having a separate operator for integer division)?

Euphoria does. In fact it can be a bit of a nuisance at times. int a,b,c a = 3 b = 4 c = a / b -- Fails 'cos result is a floating number and you can't assign it to an integer. c = floor(a / b) -- Okay now. -- Derek (skype: derek.j.parnell) Melbourne, Australia 19/11/2007 6:08:19 PM
Nov 18 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 11/18/07, Lars Noschinski <lars-2006-1 usenet.noschinski.de> wrote:
 * Stas Sergeev <stsp aknet.ru> [07-11-18 22:10]:
I haven't used D yet, but I know that most
(or all?) of the C-unrelated languages do
that in a proper way, and even the Python
developers are going to fix that in the future.

Which languages do that (without having a separate operator for integer division)?

PHP does. But then, PHP doesn't have statically typed variables, so maybe that doesn't count.
Nov 18 2007
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Stas Sergeev wrote:
 Hi.
 
 This is basically an out of curiosity.
 I wonder how does D handle the integer division.
 In C, as we all know, the following:
 int a = 3;
 int b = 5;
 float c = a / b;
 will give the result that will beat the ghost
 out of any mathematician (unless you cast
 one of the operands to float, of course).
 I haven't used D yet, but I know that most
 (or all?) of the C-unrelated languages do
 that in a proper way, and even the Python
 developers are going to fix that in the future.
 
 So the question is: how does D handle that?
 Was it infected by the Cish way of handling
 an integer division (if so - why?), or managed
 to get rid of that legacy thingy?

Comparing with dynamically typed languages like Python isn't useful because in Python a/2 can return an integer for if a==4 a float if a==5. A statically typed language like D doesn't have that luxury. Anyway, that said, I think it'd be nice to have / do float division, and introduce another operator (like python's //) for truncated integer division. But I think Walter is too entrenched in C-ish ways to see any value in changing how it works. Python is changing because it wants to be newbie/scientist friendly above all else. D merely wants to be easier to use than C++. There's a lot of territory between "newbie-friendy" and "easier than C++". In particular "has pointers" and "newbie-friendly" tend to keep their distance from one another. --bb
Nov 18 2007
parent reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
Bill Baxter Wrote:

 Stas Sergeev wrote:
 Hi.
 
 This is basically an out of curiosity.
 I wonder how does D handle the integer division.
 In C, as we all know, the following:
 int a = 3;
 int b = 5;
 float c = a / b;
 will give the result that will beat the ghost
 out of any mathematician (unless you cast
 one of the operands to float, of course).
 I haven't used D yet, but I know that most
 (or all?) of the C-unrelated languages do
 that in a proper way, and even the Python
 developers are going to fix that in the future.
 
 So the question is: how does D handle that?
 Was it infected by the Cish way of handling
 an integer division (if so - why?), or managed
 to get rid of that legacy thingy?

Comparing with dynamically typed languages like Python isn't useful because in Python a/2 can return an integer for if a==4 a float if a==5. A statically typed language like D doesn't have that luxury. Anyway, that said, I think it'd be nice to have / do float division, and introduce another operator (like python's //) for truncated integer division. But I think Walter is too entrenched in C-ish ways to see any value in changing how it works. Python is changing because it wants to be newbie/scientist friendly above all else. D merely wants to be easier to use than C++. There's a lot of territory between "newbie-friendy" and "easier than C++". In particular "has pointers" and "newbie-friendly" tend to keep their distance from one another. --bb

Here's another (non-D?) thought. How about overloading on the return type? In a strongly typed language its only convention that makes the return type somehow special. I believe the original reason for return values being special may have been that they are the only things left on the stack when returning from a function call. This was only true early on when all arguments were passed by value. We don't seem to have moved beyond that, we only tease around the edges with covariant returns and returning multiple values but semantically there's no difference between: void divide(in T numerator, in T denominator, out T result) and T divide(in T numerator, in T denominator) where T = any numeric type So why do we still insist on it in modern languages? Regards, Bruce.
Nov 18 2007
next sibling parent reply 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
Bruce Adams wrote:
 Bill Baxter Wrote:
 Stas Sergeev wrote:
 Hi. [...] So the question is: how does D handle that? Was it
 infected by the Cish way of handling an integer division (if so -
 why?), or managed to get rid of that legacy thingy?



It's a legacy think, yup! But not everything that is old is bad... the rules didn't evolve like that for no reason.
 Comparing with dynamically typed languages like Python isn't useful 
 because in Python a/2 can return an integer for if a==4 a float if
 a==5. A statically typed language like D doesn't have that luxury.
 
 Anyway, that said, I think it'd be nice to have / do float division,
 and introduce another operator (like python's //) for truncated
 integer division.  But I think Walter is too entrenched in C-ish ways
 to see any value in changing how it works.  Python is changing because
 it wants to be newbie/scientist friendly above all else.  D merely
 wants to be easier to use than C++.  There's a lot of territory
 between "newbie-friendy" and "easier than C++".  In particular "has
 pointers" and "newbie-friendly" tend to keep their distance from one
 another.
 
 --bb

Here's another (non-D?) thought. How about overloading on the return type? In a strongly typed language its only convention that makes the return type somehow special. I believe the original reason for return values being special may have been that they are the only things left on the stack when returning from a function call. This was only true early on when all arguments were passed by value. We don't seem to have moved beyond that, we only tease around the edges with covariant returns and returning multiple values but semantically there's no difference between: [...] So why do we still insist on it in modern languages? Regards, Bruce.

Return type overloading is not practical, or at least not without solving a few problems first. What return type would you expect from the function? Okay, in an assignment it's clear. What about function calls in expressions? What if you have overloaded foo to return int or float, and bar to return int or float. Then go and call bar(foo())... oooopsie! =) And it's not always as easy as just int or float; think arbitrary types! Okay, there are solutions to all this, but the only reasonable ones I know need extra hints for the compiler (some kind of syntax extension, or building a new semantic upon an available syntax). Regards, Frank
Nov 18 2007
parent 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
0ffh wrote:
 What if you have overloaded foo to return int or float, and bar to return
 int or float. Then go and call bar(foo())... oooopsie! =)

Ooopsie, I meant "bar to /take/ int or float"... take a laugh on me, everyone who spottet it! ;-) Regards, frank
Nov 18 2007
prev sibling parent Lionello Lunesu <lio lunesu.remove.com> writes:
 void divide(in T numerator, in T denominator, out T result) 
 
 and
 
 T divide(in T numerator, in T denominator)
 
 where T = any numeric type
 
 So why do we still insist on it in modern languages?

Have to agree with Bruce on this one. In fact, perhaps D could do something similar to that array trick (void bla(T[]); T[] ar; ar.bla;) for the return value of a function: void bla(out T); T t = bla; (Isn't that similar to what the return value optimization does, by the way?) L.
Nov 19 2007
prev sibling parent reply renoX <renosky free.fr> writes:
Stas Sergeev a écrit :
 Hi.
 
 This is basically an out of curiosity.
 I wonder how does D handle the integer division.
 In C, as we all know, the following:
 int a = 3;
 int b = 5;
 float c = a / b;
 will give the result that will beat the ghost
 out of any mathematician (unless you cast
 one of the operands to float, of course).

Yep, this is a trap which catch probably all C beginners.
 I haven't used D yet, but I know that most
 (or all?) of the C-unrelated languages do
 that in a proper way, and even the Python
 developers are going to fix that in the future.

 So the question is: how does D handle that?
 Was it infected by the Cish way of handling
 an integer division (if so - why?), or managed
 to get rid of that legacy thingy?

In a statically typed language, the issue is which float type do you use for (int / int)? For accuracy, it ought to be one with biggest precision, but it's also the slowest, and can be non-portable (x86 has 80-bit float, other CPU do not) So I came to the conclusion so that maybe removing the / for int/int is the only thing to do as it's too ambiguous.. Instead using operators like idiv, fdiv, f64div may be a solution. renoX
Nov 19 2007
parent reply Stas Sergeev <stsp aknet.ru> writes:
renoX Wrote:
 In a statically typed language, the issue is which float type do you use 
 for (int / int)?
 For accuracy, it ought to be one with biggest precision, but it's also 
 the slowest, and can be non-portable (x86 has 80-bit float, other CPU do 
 not)

For example, doing an integer calculus, you can get an overflow, because the compiler does not promote ints to long-longs for you. So if you have a very large values, you have to explicitly notify the compiler by doing casts. OTOH, it does promote the shorts to ints for you, when needed. Same is here: the float can be used by default, and if you really need a hight precision, then you have to resort to an explicit casts, I think.
Nov 19 2007
parent reply "David B. Held" <dheld codelogicconsulting.com> writes:
Stas Sergeev wrote:
 renoX Wrote:
 In a statically typed language, the issue is which float type do you use 
 for (int / int)?
 For accuracy, it ought to be one with biggest precision, but it's also 
 the slowest, and can be non-portable (x86 has 80-bit float, other CPU do 
 not)

I don't think this is really a problem. For example, doing an integer calculus, you can get an overflow, because the compiler does not promote ints to long-longs for you. So if you have a very large values, you have to explicitly notify the compiler by doing casts. OTOH, it does promote the shorts to ints for you, when needed. Same is here: the float can be used by default, and if you really need a hight precision, then you have to resort to an explicit casts, I think.

The main problem is that as much as we would like to idealize and abstract away details about the representations of our numbers, that is simply not practical, even on GFLOPS desktops. We *do* have to know the sizes of our numbers and whether they are integral or floating-point types. It matters a *lot* in almost every operation you perform. From a number theory perspective ints and floats are a world apart. It is true that integers are not a field because they are not closed under /. However, that does not mean we should pretend that Z == R and force float opDiv(int, int). The reality is that int != Z, either. No, int == Z_2^32, and that *does* have a closed /, which makes it as much a field as R, and deserving of its own int opDiv(int, int). Of course, the / defined on Z_n is different from int opDiv(int, int), but let us not concern ourselves with that minor detail. The fact of the matter is that computers are *not* Turing machines. They have finite tapes, and the squares of those tapes have finite sizes. And the operation of these putative TMs are sensitive to the size of the tape and the squares composing the tape. No competent programmer can ignore this reality. We have overflow and underflow and modular arithmetic on integral types. That is fundamental to ALUs and will remain so for the forseeable future. Trying to hide these facts from the user by defining float opDiv(int, int) is not doing her any favors. FP arithmetic is expensive, and using it should be explicit, not implicit. It's easy enough to define your own float div(int, int) function that gives the desired behavior. And if you are bothered that it doesn't look like normal /, I would call that a feature and a benefit. Dave
Nov 20 2007
parent reply Lars Noschinski <lars-2006-1 usenet.noschinski.de> writes:
* David B. Held <dheld codelogicconsulting.com> [07-11-20 10:31]:
From a number theory perspective ints and floats are a world apart.  It is true 
that integers are not a field because they are not closed under /.  However, 
that does not mean we should pretend that Z == R and force float opDiv(int, 
int).  The reality is that int != Z, either.  No, int == Z_2^32, and that 
*does* have a closed /, which makes it as much a field as R, and deserving of 
its own int opDiv(int, int).  Of course, the / defined on Z_n is different from 
int opDiv(int, int), but let us not concern ourselves with that minor detail.

Z_2^32 is not a field, and it has not got a division; e.g. 2^31 * z != 1 for all z \in Z_2^32.
Nov 20 2007
parent "David B. Held" <dheld codelogicconsulting.com> writes:
Lars Noschinski wrote:
 * David B. Held <dheld codelogicconsulting.com> [07-11-20 10:31]:
 From a number theory perspective ints and floats are a world apart.  
 It is true that integers are not a field because they are not closed 
 under /.  However, that does not mean we should pretend that Z == R 
 and force float opDiv(int, int).  The reality is that int != Z, 
 either.  No, int == Z_2^32, and that *does* have a closed /, which 
 makes it as much a field as R, and deserving of its own int opDiv(int, 
 int).  Of course, the / defined on Z_n is different from int 
 opDiv(int, int), but let us not concern ourselves with that minor detail.

Z_2^32 is not a field, and it has not got a division; e.g. 2^31 * z != 1 for all z \in Z_2^32.

Ah, Z_p is only a field when p is prime...yes, that's a noob error. I suspected as much, but I didn't work very hard to verify it. Let's discard one of the bit patterns and say that int == Z_2^32-1. ;) Conceptually speaking, it's pretty close to true. Dave
Nov 20 2007