djones@megatest.UUCP (Dave Jones) (11/05/88)
As is Mr. Switzer, I too am absolutely certain that I know how / and % should be defined for negative dividends. Peculiar that we should not agree! :-) We agree on the MOD issue, but not on DIV. Or maybe not. First he says that IBM "did it right": > The PC/RT implements / to truncate to smaller values and i%n to always > return a value (0..n-1) for positive "n" But then he says, > Please, do not argue that integer -1/2 should be -1... But that is, or course, truncation toward a smaller value. (-1 is smaller than -0.5) Perhaps he will want to clarify. I have given the matter quite a bit of thought, ever since 1979, only months after having obtained an M.S. in math, when I was appalled to discover that the Pascal implementation at my new place of employment calculated -1 MOD 2 to be a negative number! Sheesh. I have since become resigned to the fact that, as the saying goes, "S**t happens." I am well aware of the fact that writing portable code means recognizing that most C compilers don't do it the way I would like it. But I still have strong opinions on the subject, as to what the most practical definitions of DIV and MOD are. It is no coincidence that they happen to be the theoretical definitions as well. I really find it quite astonishing that there is no consesus on this. It just looks so obvious. There is one way that is beautifully consistent. All the other ways have hair. In case you have not figured it out, my vote is along these lines: -1 % 2 == 1 -1 / 2 == -1 It is not a coincidence that these are the same numbers that you get from -1 & 1 == 1 -1 >> 1 == -1 provided that the >> operator does sign extension properly on signed integers. The operations of shifting and masking are intimately related to the arithmetic operations of counting. It has long been a source of delight and insight for me to take notice of the striking correspondences between, for example, addition of numbers and disjoint union of sets -- between masking bits and orthogonal projections in inner-product spaces -- between the algebra of continued fractions and the algebra of solving regular expressions -- to name just a few examples. I propose that if j > 0 then i/j be truncated downward -- by that I do not mean "toward zero" -- and that i%j is a number in the range 0..(j-1). We will return to the matter of i % (-j) and i/(-j) in a couple of exercises later on. (I'll give my answers in a spoiler at the very bottom.) Okay, now to reality. By what criteria would we choose these conventions? What are the practical considerations? In practice, what one wants is to be able to do calculations that do not require checking the signs of numbers. Also nice is to use shifts and and negation to optimize code when divisors and multipliers are positive multiples of two. This can be done by compilers or by knowledgable/devious programmers (depends on your point of view), provided that the conventions allow it unambiguously. You can even extend this to non- powers of two, by using shifts and adds for multiplication. But if your definition of DIV or MOD refers to the function ABS, as does the ANSII Pascal standard, it is pretty likely that checking the sign (or equivalently, calling ABS) will be required. The ABS function has a nasty non-linearity at zero. It is equivalent to say that "changing the sign of the dividend changes sign of the quotient, but not the magnitude," becuase there is an implicit "ABS" in the word "magnitude". Look at the graph of the the functions for DIV2 and MOD3, as I propose them, and you will see that they breeze through zero without taking any notice of it, whatsoever. DIV2 2 X----X . . . . . . . . 1 X----X . . . . . . . . |....|....|....|....X----X....|....|....|....| -4 -3 -2 -1 0 1 2 3 4 5 . . . . . . X----X -1 . . . . . . . . X----X -2 Notice that the X's form a neat stairstep with a slope of 1/2. Everywhere you look at it, it looks exactly the same. There is nothing peculiar happening about zero. The competing graph has one "step" that is three units in length: -1, 0, 1. All the other steps are two units long, just as one would expect of an integral graph with slope 1/2. MOD3 X 2 X X / . / / / . / / / . / / X 1 X X / . / / / . / / / ./ / X X X -4..-3..-2..-1..0...1...2...3...4...5 . . A nice, regular "ramp function". Again, there is nothing special about zero. The function looks the same everywhere. The competing graph "flips over" at zero. So if we use these definitions, we never have to check the sign of a dividend. Notice also that i == (i/j)*j + i%j holds for all i, positive and negative alike, when j>0. Same reason. Nothing out of the ordinary happens at zero. So how about those nutty negative divisors, eh? Let's call the property i == (i/j)*j + i%j the "Chinese Remainder" property, after the "Chinese Remainder Theorem" of number theory. EXERCISE 1. Propose a definitive graph demonstrating the truncation properties of the function DIV_minus_2. What alternatives did you consider? Why did you choose the one you did? How does it extend the principal of truncation? EXERCISE 2. Can the definition of MOD be extended to include negative divisors? If so, propose a definitive graph for MOD_minus_3. Does it, along with your definition from exercise, 1 have the Chinese Remainder property? Spoilers follow. Answer 1. To obtain a DIV_minus_n graph, flip the DIVn graph about the X-axis, so that the stairsteps slope down going left-to-right, rather than up. Sybolicly, define i/(-j) as -(i/j). Thus truncation of dividends is downward for positive divisors, and upward for negative divisors. They tend to "slip down the stairstep" quite consistently. Answer 2. Define i%(-j) as i%j. The Chinese Remainder property is preserved by these definitions.
ok@quintus.uucp (Richard A. O'Keefe) (11/08/88)
In article <972@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
This is an issue which has been thrashed out many times over the years.
Back issues of SigPlan Notices are a good place to look.
As Every Schoolboy Knows, there are at least three sensible definitions of
integer division/remainder, all of which agree which divisor and dividend
are positive. Common Lisp provides all three, and a fourth, also sensible.
Note that the Pascal standard does not define integer division and
remainder for non-positive divisors.
sjs@jcricket.ctt.bellcore.com (Stan Switzer) (11/08/88)
In article <972@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: > As is Mr. Switzer, I too am absolutely certain that I know > how / and % should be defined for negative dividends. Peculiar > that we should not agree! :-) We agree on the MOD issue, but > not on DIV. Or maybe not. First he says that IBM "did it right": > > Please, do not argue that integer -1/2 should be -1... > But that is, or course, truncation toward a smaller value. > (-1 is smaller than -0.5) > Perhaps he will want to clarify. OOPS! I goofed. I meant 0 not -1. I agree completely with your followup. One day while I was hacking Postscript it occurred to me to see if Adobe was clever enough to do it right. After all, grapgics is one of the areas where it really matters how / and % work. I am sad to say that Postscript does it wrong too. And here it is impossible to blame the hardware, as the cost of making it work right would be insignificant compared to the interpreter overhead. Stan Switzer sjs@ctt.bellcore.com
mcdonald@uxe.cso.uiuc.edu (11/09/88)
> -1 >> 1 giving -1
Odd. Lets see here. In binary 4 bits 1 == 0001b
0 == 0000b
-1 == 1110b
with zero filling shift -1 >> 1 == 0111b == 7
with sign filling shift -1 >> 1 == 1111b == -0
neither of which are == -1. Perhaps you are unfamiliar with this
relatively common method. On some machines -1 >> 1 == -1, but not
all machines - and not necessarily in ANSI C.
:-) :-) :-)
djones@megatest.UUCP (Dave Jones) (11/09/88)
From article <643@quintus.UUCP>, by ok@quintus.uucp (Richard A. O'Keefe): > This is an issue which has been thrashed out many times over the years. No doubt. > Back issues of SigPlan Notices are a good place to look. Sigplan Notices is one of the most prolific sources of nonsense in all Computerdom. > > As Every Schoolboy Knows, there are at least three sensible definitions of > integer division/remainder, all of which agree which divisor and dividend > are positive. Being an [ex] schoolboy (and an [ex] associate prof of computer sci, who taught quite a few of the schoolboy's), I know about the competing definitions. But this exschoolboy finds all but one of them to be seriously flawed. Maybe I'll start a political movement to enforce my opinions. I'll call it a "Standards Committee". Yeah. I can see it now: "Just say NO to negative remainders and rounding toward zero."
djones@megatest.UUCP (Dave Jones) (11/09/88)
I've figured it out! This whole deficit thing is due to a misdefinition of DIV and MOD. Dig it. Let's say there's a club with ten members. So the chairman comes in and sez, "Okay, we owe 19 skillion dollars. Let's divide up the debt, and pay it off." Let's see now... -1 skil. --------- 10) -19 skil. We each owe one skillion dollars. And the _good_ news is that *we*have*a*remainder!
ok@quintus.uucp (Richard A. O'Keefe) (11/09/88)
In article <982@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: >From article <643@quintus.UUCP>, by ok@quintus.uucp (Richard A. O'Keefe): >> Back issues of SigPlan Notices are a good place to look. >Sigplan Notices is one of the most prolific sources of nonsense in >all Computerdom. It doesn't *begin* to compare with comp.lang.c and other newsgroups (:-). There has been a *lot* of good stuff in Sigplan notices. Even some of the bad advice repays careful study to see _why_ it's bad. (I have learned a lot by saying "this is trash" and having someone ask me "why?") >> As Every Schoolboy Knows, there are at least three sensible definitions of >> integer division/remainder, all of which agree which divisor and dividend >> are positive. > >Being an [ex] schoolboy (and an [ex] associate prof of computer sci, who >taught quite a few of the schoolboy's (sic)), I know about the competing definitions. >But this exschoolboy finds all but one of them to be seriously flawed. I thought that when I capitalised "as every schoolboy knows" it could manage without a smiley. It's a well-known catchphrase, after all. BE MORE SPECIFIC. Say *why* you find all the other definitions "seriously flawed". (I can see how a definition can be useless, or awkward, or hard to understand, or difficult to implement in a programming language. But "flawed"?) By the way, whatever sensible definition of remainder one adopts, MOST_NEGATIVE_INTEGER % (-1) ought to be 0 (*anything* % (-1) should be 0). I can imagine implementations (e.g. on an IBM System/370) where the result might be an interrupt, and I know of one machine where the obvious translation would yield rubbish.
turner@sdti.UUCP (Prescott K. Turner) (11/10/88)
In article <643@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes: >As Every Schoolboy Knows, there are at least three sensible definitions of >integer division/remainder, all of which agree which divisor and dividend >are positive. To call all three definitions "sensible" is inviting a war. To me the arguments Dave Jones presented make sense and the counterarguments do not. Actually, I do accept as a counterargument that most programming languages require the definition in which the quotient is truncated towards 0. But it's a shame that they went down that path. >Note that the Pascal standard does not define integer division and >remainder for non-positive divisors. The Pascal standard defines integer division for all divisors except 0. Standard Pascal's "mod" operator does not give the remainder from "div", even for positive divisors. The committee decided that while "div" had to be like all of the other languages, "mod" should be sensible. -- Prescott K. Turner, Jr. Software Development Technologies, Inc. 375 Dutton Rd., Sudbury, MA 01776 USA (508) 443-5779 UUCP:...genrad!mrst!sdti!turner
djones@megatest.UUCP (Dave Jones) (11/10/88)
From article <225800089@uxe.cso.uiuc.edu>, by mcdonald@uxe.cso.uiuc.edu: [ Description of one's complement arithmetic omited. } > Perhaps you are unfamiliar with this > relatively common method. On some machines -1 >> 1 == -1, but not > all machines - and not necessarily in ANSI C. > > > :-) :-) :-) Nah. I'm familiar with it. I just thought maybe if I closed my eyes, it would go away, along with all those communist-inspired negative remainders. Here. Have a smiley on me: :-) Dave J.
ok@quintus.uucp (Richard A. O'Keefe) (11/11/88)
In article <328@sdti.UUCP> turner@sdti.UUCP (0006-Prescott K. Turner, Jr.) writes: >In article <643@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes: >>there are at least three sensible definitions of integer division/remainder, >>all of which agree which divisor and dividend are positive. >To call all three definitions "sensible" is inviting a war. Not at all: to agree that what someone else wants to do is sensible is usually a rather irenic thing to do. >To me the arguments Dave Jones presented make sense and the >counterarguments do not. I claim that each of the "floor", "trunc", and "ceil" definitions is sensible and useful. I have realistic (got to conceal those proprietary details) examples showing that each of them has uses. Please don't think that I ever suggested that any of the definitions other than your favourite should be used _instead_. I repeat that I have uses for all three. (And if there are other sensible definitions around, I can probably find uses for them too.) Dave Jones' arguments, and arguments I have received by E-mail from someone else, boil down to "_I_ haven't had the wit to see a use for it, so it's _baaaad_." >Actually, I do accept as a counterargument that most programming languages >require the definition in which the quotient is truncated towards 0. re >But it's a shame that they went down that path. Well, programming language designers mostly copy other languages. And way back there we find Fortran. And Fortran's designers either ruled the way they did because they were convinced that it was the most useful definition for Fortran's then envisaged applications, or because it suited the hardware well, and in the latter case the designers of the 704 or whatever presumably had what _they_ thought were good reasons for their choice. "Most programming languages require definition X" is some sort of argument for making definition X available, but it is _not_ a good argument for having X be the _only_ definition available. I don't give a Continental which particular definition a language designer choses to dignify with infix notation of its own, as long as when I have a use for one of the others it is available at least as efficiently as any- thing I could have coded myself. It is worth noting that on a lot of present-day UNIX boxes (68010s, 68020s, VAXen, many but not all RISCs) that integer division is so slow anyway that providing the hardware version (whatever that is) as "/" and "%" and supporting the other three definitions with a few conditional branches and other in-line code would be a perfectly reasonable thing to do.
dik@cwi.nl (Dik T. Winter) (11/12/88)
In article <664@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes: > Well, programming language designers mostly copy other languages. And way > back there we find Fortran. And Fortran's designers either ruled the way > they did because they were convinced that it was the most useful definition > for Fortran's then envisaged applications, or because it suited the > hardware well, and in the latter case the designers of the 704 or whatever > presumably had what _they_ thought were good reasons for their choice. > I do not think that earlier versions of Fortran gave a precise specification of the semantics of DIV (earlier versions of Fortran were not precise enough anyway). And yes, truncating to zero matched machines best in those times, with 9's complement or sign-magnitude. -- dik t. winter, cwi, amsterdam, nederland INTERNET : dik@cwi.nl BITNET/EARN: dik@mcvax
djones@megatest.UUCP (Dave Jones) (11/12/88)
From article <664@quintus.UUCP>, by ok@quintus.uucp (Richard A. O'Keefe): > Dave Jones' arguments, and arguments I have received by E-mail from > someone else, boil down to > "_I_ haven't had the wit to see a use for it, so it's _baaaad_." > [ Author's note: The following has undergone four rounds of toning down. ] I suggest that the reader compare the two postings side by side and determine for themselves which speaks to mathematical utility and which makes unsubstantuated value claims. I also hope that in the future, Mr. O'Keefe will refrain from impugning the "wit" of fellow participants. Best regards, Dave J.
ok@quintus.uucp (Richard A. O'Keefe) (11/13/88)
In article <1003@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: >From article <664@quintus.UUCP>, by ok@quintus.uucp (Richard A. O'Keefe): >> Dave Jones' arguments, and arguments I have received by E-mail from >> someone else, boil down to >> "_I_ haven't had the wit to see a use for it, so it's _baaaad_." >I suggest that the reader compare the two postings side by side >and determine for themselves which speaks to mathematical utility >and which makes unsubstantuated value claims. > >I also hope that in the future, Mr. O'Keefe will refrain from >impugning the "wit" of fellow participants. I did take the trouble to write several pages of mathematical-style justification, but decided that it would be a waste of bandwidth to post it. I will here show four examples: Given a block of memory N bytes long, and M objects to distribute it among, how much can each object have? Answer = floor(N/M) [definition 1] How much memory will not be allocated to any object? Answer = N-floor(N/M)*M = N "floor-mod" M Given that I need N bytes of memory, but that I have to ask for pages M bytes long, how many pages should I ask for? Answer = ceil(N/M) [definition 2] How much excess memory did I have to ask for? Answer = ceil(N/M)*M-N = -(N "ceil-mod" M) I have an axis ranging from 0 to N (sign unknown) which I want to divide into M "full" buckets with perhaps one "partial" bucket left over. What should the width of each full bucket be? Answer = trunc(N/M) = N div M [definition 3] How wide will the partial bucket be? Answer = N-trunc(N/M)*M = N mod M Which integer most accurately approximates N/M? Answer = round(N/M) [definition 4] What is the error in this approximation? Answer = N-round(M/M)*M = N "round-mod" M. I did not impugn anyone's wit at all, I was attacking the form of their arguments. No amount of showing that a particular definition is useful will show that other definitions are _not_ useful. Nor is it legitimate to claim that certain mathematical properties useful for _some_ application are essential for _all_ uses of division. All that the "speaking to mathematical utility" amounted to may fairly be paraphrased as "I find this definition useful and don't see how to use another, so another definition is bad". For example, one person claimed that an essential property of remainder was that X (mod N) classify all integers X into N equivalence classes. That is a very useful property indeed, and definition 3 lacks it. But there are applications (like the one shown) where that property is _not_ needed, and demanding that _the_ remainder operation have it really doesn't help. Honestly, friends, each of the four versions of integer division (and its corresponding remainder) shown above has its uses. I find myself wanting _each_ of them (though I have to admit that I want [4] less often than the others, but what of that? another programmer may have other needs). A compiler could generate more efficient code for them (whatever the hardware support for division) than I could. I don't care which of them gets the privilege of having its own infix notation and update operator, I just wish they were all available _somehow_. [It might be a good idea to reserve the infix notation for when it doesn't matter whether you're using floor or trunc, then the compiler could pick whichever was more efficient.]