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
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 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 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 next sibling parent reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
0ffh Wrote:

 Bruce Adams wrote:
 
 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
The obvious thing to do would be to require explict qualification when there is an ambiguity. For everything else the types are sufficient cues. I suspect what is required is type inference a la ML. So in the case of (in the following feel free to replace X with divde, Y with print and R with random if that makes it easier to read). int X(int a) long X(long b) void Y(int y) void Y(long y) void Z(int y) void Q(long y) int a = 1; long b = 2; Z(X(a)) is legal (no ambiguity) Q(X(b)) is legal (no ambiguity) Y(X(a)) - infer use of Y(int) because X(int) because a = int Y(X(b)) - infer use of Y(long) because X(long) because b = long The only place you have real ambiguity is: int R(void) long R(void) so X(R()) is ambiguous and should thus cause a compile error. It must be replaced with either: int temp = R(); X(temp) or X(cast(int)R()) This is trivial to implement in a compiler the type inference is a little more tricky (though Walter did say he was interested in adding functional programming features to D ;-). I think a good syntactic sugar to use for that would be named parameters, which are useful for so many other reasons (but much less trivial to implement) So Y(int Int) Y(long Long) would allow X(Y(Int)) unfortunately this doesn't solve the problem for R because the return type cannot be named So casting cannot be eliminated entirely that way but it can be significantly reduced. That's got to be a good thing surely? Regards, Bruce.
Nov 18 2007
parent reply 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
Bruce Adams wrote:
 So casting cannot be eliminated entirely that way but it can be
 significantly reduced. That's got to be a good thing surely?
Well, the use of a cast as hint for the compiler looks like a rather nice choice. But then I don't quite see how it improves the thing about integer and float division apart from the case of assignments. Take: void foo(int); void foo(float); As it is now, I have for example int i,j; float f; [...] i=i/j; // implicit int f=cast(float)i/j; // explicit float foo(i/j); // implicit int foo(cast(float)i/j); // explicit float With return type overloading I get int i,j; float f; [...] i=i/j; // implicit int f=i/j; // implicit float foo(i/j); // compiler error: under-determined type information foo(cast(int)i/j); // explicit int foo(cast(float)i/j); // explicit float So now there are just different cases where a cast is needed. For some people I am sure the case with overloaded return types has more appeal, but for others it is different. It's just a matter of tastes, really, as the C way is no more complicated than the other way. It is just not what many people expect at first. I can't yet see how this small improvement is worth the trouble implementing. Regards, frank
Nov 18 2007
next sibling parent 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
0ffh wrote:
 With return type overloading I get
   [...]
   foo(cast(int)i/j); // explicit int
   foo(cast(float)i/j); // explicit float
Oops; this is with syntactic sugar, BTW, as I was just casting the first operand, not the expression. Otherwise foo(cast(int)(i/j)); // explicit int foo(cast(float)(i/j)); // explicit float (The current style example should work as it is.) Regards, Frank
Nov 18 2007
prev sibling parent reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
0ffh Wrote:

 Bruce Adams wrote:
 So casting cannot be eliminated entirely that way but it can be
 significantly reduced. That's got to be a good thing surely?
Well, the use of a cast as hint for the compiler looks like a rather nice choice. But then I don't quite see how it improves the thing about integer and float division apart from the case of assignments. Take: void foo(int); void foo(float); As it is now, I have for example int i,j; float f; [...] i=i/j; // implicit int f=cast(float)i/j; // explicit float foo(i/j); // implicit int foo(cast(float)i/j); // explicit float With return type overloading I get int i,j; float f; [...] i=i/j; // implicit int f=i/j; // implicit float foo(i/j); // compiler error: under-determined type information foo(cast(int)i/j); // explicit int foo(cast(float)i/j); // explicit float So now there are just different cases where a cast is needed. For some people I am sure the case with overloaded return types has more appeal, but for others it is different. It's just a matter of tastes, really, as the C way is no more complicated than the other way. It is just not what many people expect at first. I can't yet see how this small improvement is worth the trouble implementing. Regards, frank
Well I wasn't advocating a change to D (yet). Hence the non D in my original post. It was more a thought experiment. Your use case above is certainly a compelling reason not to do it this way, at least for division. I wonder if there is not a way of having the best of both worlds. Still, I begin to see why others want a seperate div operator. I shall ponder some more...
Nov 18 2007
parent reply 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
Bruce Adams wrote:
 0ffh Wrote:
 With return type overloading I get
 
 int i,j; float f; [...] i=i/j; // implicit int f=i/j; // implicit 
 float foo(i/j); // compiler error: under-determined type information 
 foo(cast(int)i/j); // explicit  int
 foo(cast(float)i/j); // explicit float
 [...btw. thunderbird rewrapping does strange things to those lines...]
Well I wasn't advocating a change to D (yet). Hence the non D in my original post. It was more a thought experiment. Your use case above is certainly a compelling reason not to do it this way, at least for division. I wonder if there is not a way of having the best of both worlds. Still, I begin to see why others want a seperate div operator. I shall ponder some more...
Far be it from me to add to the plethora of D feature requests, but one possible solution might be giving an explicit precedence hierarchy to the compiler at one point, e.g. void foo(int){...} void foo(float){...} precedence foo(float) > foo(int); could in case of ambiguity choose float over int. But I'm not quite sure this could not backfire in some way... Regards, frank
Nov 18 2007
parent 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
0ffh wrote:
 precedence foo(float) > foo(int);
Nah, that's bull shite. We were talking return type overloading, so make that precedence float opDiv(int,int) > int opDiv(int,int); Good thing is, in my code I could adhere to the classic way. =) regards, frank (sleepy)
Nov 18 2007
prev sibling next sibling parent reply Stas Sergeev <stsp aknet.ru> writes:
Bill Baxter Wrote:
 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.
Of course, but there is no problem to make the / op to just always return float, or is there?
 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.
For what? You either write: int c = a / b; or: float c = a / b; Both seem to perfectly express the intention, so what is the new operator may be good for? Currently, the later expression simply makes no sense. I don't even think it is present in some code. So I don't think there will be any confusion or the compatibility breakage even.
Nov 18 2007
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Stas Sergeev wrote:
 Bill Baxter Wrote:
 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.
Of course, but there is no problem to make the / op to just always return float, or is there?
 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.
For what? You either write: int c = a / b; or: float c = a / b; Both seem to perfectly express the intention, so what is the new operator may be good for?
Which flavor of division is being used here? void do_something(int x) { ... } void do_something(float x) { ... } do_something(a/b); --bb
Nov 18 2007
prev sibling parent reply Lars Noschinski <lars-2006-1 usenet.noschinski.de> writes:
* Stas Sergeev <stsp aknet.ru> [07-11-19 06:46]:
Bill Baxter Wrote:
 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.
Of course, but there is no problem to make the / op to just always return float, or is there?
Efficiency and accuracy. An integer division is faster than a float division. Also, not all integer values can be represented exactly as floats.
Nov 19 2007
next sibling parent reply Stas Sergeev <stsp aknet.ru> writes:
Lars Noschinski Wrote:
Of course, but there is no problem to make the / op to
just always return float, or is there?
Efficiency and accuracy. An integer division is faster than a float division.
But isn't it just an optimization issue? The compiler is supposed to know the result type beforehand, is it not? It then can decide whether it needs the float calculations or not. And in a more complex cases, the one can hint the compiler to not use float calculation by explicit casts to int, like this: int a = (int)(b / c) * 500; This expression can still be compiled without the fp math. And the cast is not redundant here as it truncates the value, and the programmer always knows when he needs to truncate the value in his expression. He is unlikely to forget such a cast. While currently the casts like this: float a = (b / (float)c) * 500; are used only to tell the compiler about the desired type, and the programmer can easily forget to put one.
Nov 19 2007
parent reply 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
Stas Sergeev wrote:
 But isn't it just an optimization issue? The compiler is supposed
 to know the result type beforehand, is it not?
No, exactly that is the problem: The compiler knows the result type only in some cases, as has been said twice now already.
 And in a more complex cases, the one can hint the compiler
 to not use float calculation by explicit casts to int, like this:
 int a = (int)(b / c) * 500;
 This expression can still be compiled without the fp math.
 And the cast is not redundant here as it truncates the value,
 and the programmer always knows when he needs to truncate
 the value in his expression. He is unlikely to forget such a cast.
 While currently the casts like this:
 float a = (b / (float)c) * 500;
 are used only to tell the compiler about the desired type, and
 the programmer can easily forget to put one.
That tradeoff can be made. Some people might be more happy then. Some will be less happy. A lot of work will have been caused for little gain. Also: We have all understood your point. Some think the same as you, some different. As it's a matter of tastes, you won't achieve much more if you keep pressing it. This is not like wooing a woman, where you get extra points for perseverance. Regards, frank
Nov 19 2007
parent reply Stas Sergeev <stsp aknet.ru> writes:
0ffh Wrote:
 Also: We have all understood your point. Some think the same as you,
 some different. As it's a matter of tastes, you won't achieve much
 more if you keep pressing it.
I didn't think I was pressing it. The guy said that the efficiency is the problem, and I said that I don't think so (perhaps I was wrong, but where is the pressure?). As for not reading the entire thread - very probably. For some reasons the thread got "split". The fragments that I've found quickly, I've looked through, the others got slipped. :) (but search seems to help now)
Nov 19 2007
parent reply 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
Stas Sergeev wrote:
 0ffh Wrote:
 Also: We have all understood your point. Some think the same as you,
 some different. As it's a matter of tastes, you won't achieve much
 more if you keep pressing it.
I didn't think I was pressing it.
Maybe not, conceded.
 The guy said that the efficiency is the problem,
 and I said that I don't think so (perhaps I was wrong,
 but where is the pressure?).
 As for not reading the entire thread - very probably.
 For some reasons the thread got "split". The fragments
 that  I've found quickly, I've looked through, the others
 got slipped. :) (but search seems to help now)
It's just that I can't stand the long threads which are usually caused when people try to argue about things which boil down to a mere matter of preference. Those disagreements cannot, and so will not, be resolved with technical (or any other) arguments. Even if one of the possibilities were really objectively better that doesn't help much unless it's by a rather wide margin. The less difference it makes, the more unlikely it is that it's convincing, the longer and more painful it all gets. I just wanted to stop this short... =) Now to something completely different: The efficiency thing. If I make returning floats the default for integer division then it will make actual integer division slow (three casts and the float division) unless you have the compiler do type inference. Type inference is not always possible. That means we still need casts (only in different places now) plus extra logic in the compiler to achieve nothing more than changing to a different default behaviour, which is a matter of taste. Q.E.D. regards, frank
Nov 19 2007
parent 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
0ffh wrote:
 then it will make actual integer division slow (three casts
 and the float division) unless you have the compiler do type
Hrmm, probably int division and two casts would suffice, which might be reduced by the optimiser to just the division. Still, this works only for for some cases and does not invalidate the overall argument (bit like some kind of type inference through the back door, with the same weakness). regards, frank
Nov 19 2007
prev sibling parent reply Matti Niemenmaa <see_signature for.real.address> writes:
Lars Noschinski wrote:
 An integer division is faster than a float division.
This actually isn't the case on Pentium 4, at least. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Nov 20 2007
parent reply 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
Matti Niemenmaa wrote:
 Lars Noschinski wrote:
 An integer division is faster than a float division.
This actually isn't the case on Pentium 4, at least.
Even if fdiv takes as many cycles as idiv, you'll still have to add the time needed for the necessary casts. regards, frank
Nov 20 2007
parent Matti Niemenmaa <see_signature for.real.address> writes:
0ffh wrote:
 Even if fdiv takes as many cycles as idiv, you'll still
 have to add the time needed for the necessary casts.
True, there's some setup involved. I didn't check the code generated to get the exact values, but on the Pentium 4, for instance, the FDIV instruction actually takes some 5-10 cycles _less_ than the DIV/IDIV instruction. (If anybody wants to research, see http://www.agner.org/optimize/instruction_tables.pdf ) Just pointing something out. Lars's point about accuracy is more relevant than efficiency, anyway. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Nov 20 2007
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Bill Baxter:
 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++.
Pascal uses / and div, and it's a good enough syntax. (If operators get changed, then replacing && with and, || with or, etc (and maybe even | with OR, & with AND, etc), may be newbie friendly too. Even Python keeps those cryptic & | ~ ^ maybe because if you need them you can't be too much newbie). Bye, bearophile
Nov 19 2007
prev sibling next sibling parent Stas Sergeev <stsp aknet.ru> writes:
Bill Baxter Wrote:
 Of course, but there is no problem to make the / op to
 just always return float, or is there?
Which flavor of division is being used here? void do_something(int x) { ... } void do_something(float x) { ... } do_something(a/b);
Well, in case / is made to return float, then the simplest answer might be that it should use do_something(float x). But my statement about the compatibility was wrong of course...
Nov 19 2007
prev sibling next 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)
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.
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
prev sibling parent Stas Sergeev <stsp aknet.ru> writes:
0ffh Wrote:
 Hrmm, probably int division and two casts would suffice, which
 might be reduced by the optimiser to just the division.
Yes, that's exactly what I thought was a possibility.
 Still,
 this works only for for some cases
I thought in cases where it doesn't, you would need an explicit cast anyway. eg: int a = (int)(b / c) * 500; You either _need_ that cast, or you need the float math. Because the result will be different. Well, this example is probably naive, but I yet have to dig this thread more to find the counter-examples. Well, the thread went to discussing the overloading of the division operator, which is not my preference anyway.
 unless you have the compiler do type
 inference.
You know, all flavours of the optimization are taken for granted these days. :) When I try to compile my programs with the optimizer disabled, it usually became 3 times bigger and basically stops working because it became a CPU hog. :) (well, this is not about a PC progs, but about the progs for MCUs, and this basically is not my fault but gcc/avr-libc's one, but the fact is that the prog became completely unusable without an optimization).
Nov 19 2007