8

For Example,

If I write

int var;
var=-8/-5;

As per operator precedence, -8/-5 would be equivalent to ((-8)/(-5)). But will it be possible for C89 to give two values like for the case of -8/5 it can give -1 or -2. or It will treat it as the division of two positive integers?

Question is in with reference to the book by K.N.King (C Programming A modern Approach)

smci
  • 32,567
  • 20
  • 113
  • 146

4 Answers4

7

C89 has rule that if either operand is negative then the result of a division can be rounded either up or down.
C89-3.3.5:

If either operand is negative, whether the result of the / operator is the largest integer less than the algebraic quotient or the smallest integer greater than the algebraic quotient is implementation-defined, as is the sign of the result of the % operator. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.

For example in case of -8/5; output of this could be -1 ((-8)/5) or -2 (-(8/5)).
In C99 it is guaranteed to be truncated towards 0.

In your case both the operands are -ve and output will be a +ve number (either 1 or 2 in this case).

haccks
  • 104,019
  • 25
  • 176
  • 264
  • Actually I am trying to understand how can it be -2 and can't get it. – Eugene Sh. Apr 27 '18 at 19:14
  • @EugeneSh. Because that is _"largest integer less than the algebraic quotient"_ - which is one of the implementation options. The algebraic quotient -f -5/8 being -1.6 - round down (-2) or round up (-1) are both possible. It comes down to whether the general rule for integer division is _round toward zero_, or _round down_. – Clifford Apr 27 '18 at 19:17
  • @EugeneSh.; It depends on the implementation that if it apply `-` operator before division or after division. If it is applied after division then `8/5` will give `1` (`1.6` will go down and give 1). If applied before division then the result will be `-2` (`-1.6` will go down and give `-2`). – haccks Apr 27 '18 at 19:21
  • I mean I don't see how it can satisfy `(a/b)*b + a%b = a` – Eugene Sh. Apr 27 '18 at 19:23
  • 1
    @haccks : commuting -1.6 to -2 is definitely _down_ not _up_ ; -2 is _less than_ -1.6. – Clifford Apr 27 '18 at 19:25
  • @EugeneSh. : Then perhaps you should post a question; it is hard to explain in a comment and not really appropriate in a comment to someone else's answer to a _different_ question. – Clifford Apr 27 '18 at 19:33
  • @EugeneSh.; Standard says *`(a/b)*b + a%b` shall equal `a`*. `-8/5` can either be `-1` or `-2`. While `a%b` could be either `-3` or `2`. So `(a/b)*b + a%b` will be either `-1*5 + (-3)` or `-2*5 + 2`. In both cases result will be `-8` which is `a`. – haccks Apr 27 '18 at 19:35
  • @haccks OK, My mistake was that I though `-8 % 5` can be `-3` or `3` – Eugene Sh. Apr 27 '18 at 19:36
  • 1
    How could that be a standard if the rounding behaviour was optional? Good job it was revised in C99. – Weather Vane Apr 27 '18 at 19:38
  • My mind is blown; and what I considered reality has just been damaged. That `-8/-5` could ever be `2` is just bizarre. I wonder if any implementations actually did this, and if there are any bugs-in-the-wild because of this! – abelenky Apr 27 '18 at 19:43
  • @haccks what would have been the value for -8%-5 in C89? -3, 3 or 2? – Yash Catchem Apr 27 '18 at 19:51
  • @YashCatchem; It will be either `-3` or `2`. Never `3`. – haccks Apr 27 '18 at 19:54
  • 4
    @WeatherVane : Generally C _implementation defined behaviour_ is intended to be whatever is simplest or most efficient on the target platform. Whether a platform ever existed where rounding-down rather than round-toward-zero was simplest I don't know, but wide architectural variations existed in early computers, such as 1's complement and sign-and magnitude integer representations. – Clifford Apr 27 '18 at 19:55
  • @WeatherVane; I think I am not qualified enough to answer this question. – haccks Apr 27 '18 at 19:58
  • @Clifford: On most platforms, if one is dividing a number by an integer that is computed at run time, rounding toward zero is simplest. If dividing by a constant power of two, rounding down is simplest. If dividing by some other constant, either approach might be simplest. IMHO, the Standard should have made the result be an Unspecified choice between rounding toward zero or rounding down. In most cases where it would matter, it would usually be just as simple to write code to handle positive and negative cases separately as computations involving postive operands than to... – supercat May 09 '18 at 22:54
  • ...write code dealing with whatever kind of result the compiler would give from negative operands. – supercat May 09 '18 at 22:55
1

C89 allowed implementations to use any combination of rounding up and down for three of the four combinations of positive and negative operands (when both operands were positive, it mandated rounding down). At the time, most platforms performed division in a way that would make truncating for all combinations of operands more efficient than consistently using any other rounding mode for some combinations, and consequently C implementations for those platforms did likewise. This in turn lead to C99 mandating that particular behavior.

Ironically, the way many platforms now perform division (processing division by a constant as a multiply-and-shift operation), truncation is no longer the most efficient way of handling non-zero remainders, but the conventions which date back to a time when it was are now locked in stone.

supercat
  • 77,689
  • 9
  • 166
  • 211
1

What is the behavior of C89 with respect to division of two negative numbers

The quotient will be 1 or 2.

int var;
var=-8/-5;

C89 allowed a division of 2 integers (with at least one negative) that had a non-zero remainder to the higher or lower integer result. The standard library provided div() to calculate the quotient and remainder consistently across compilers without this flexibility.

div_t     div( int x, int y );

This function had a specified "truncated towards zero" which is the behavior of / since C99. This allowed for portable, if sometimes slightly inefficient, C89 code.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 1
    "This allowed for portable, if sometimes slightly inefficient, C89 code." - if this refers to the use of `div()`, it depends. On the 68000 family for example, the `DIV` machine instruction already provided both, modulus and quotient, so `div()` was actually even faster if you needed both values. And that was actually quite common these days, e.g. for graphics or software floating point emulation. We whould keep in mind at that trime, compiler optimisation was very basic at best and performance was an issue. – too honest for this site Apr 27 '18 at 19:41
  • @Olaf True about the use of `div()` provided the quotient and remainder together - often with higher performance than `/` and `%` separately - when they had the same functionality. Yet on systems that performed a non-truncated towards zero", a `/, %` pair could still beat `div()`. Certainly the best was platform/complier dependent and , as you suggest, often quite important. – chux - Reinstate Monica Apr 27 '18 at 19:55
1

From K&R second edition (circa 1988)

The binary / operator yields the quotient, and the % operator the remainder, of the division of the first operand by the second; if the second operand is 0, the result is undefined, Otherwise, it is always true that (a/b)*b + a%b is equal to a. If both operands are non-negative then the remainder is non-negative and smaller than the divisor; if not, it is guaranteed only that the absolute value of the remainder is smaller than the absolute value of the divisor.

For example, to compute -8/-5 (under the C89 rules), we first need to compute -8%-5. The specification allows two possible answers for the remainder: -3 and 2. Both satisfy the requirement that the absolute value of the remainder is smaller than the absolute value of the divisor, and both satisfy the requirement that (a/b)*b + a%b equals a.

(-8/-5)*-5 + -3 = -8    ==>    (-8/-5) = 1     since    (1)*-5 + -3 = -8
(-8/-5)*-5 +  2 = -8    ==>    (-8/-5) = 2     since    (2)*-5 +  2 = -8

So the result of division was allowed (by C89) to have two different answers, because (assuming negative a or b) the result of the remainder operator % could either be negative or positive. This was fixed in C99, which requires division to truncate towards 0.


For those more mathematically inclined, note that

-3 ≣ 2 mod(5)

https://en.wikipedia.org/wiki/Congruence_relation

user3386109
  • 34,287
  • 7
  • 49
  • 68
  • 1
    So the problem *was* that the definition of `/` was dependent on definition of `%` and vise versa. – Eugene Sh. Apr 27 '18 at 19:46
  • @EugeneSh. Yup, the real mind bender was `-8 % -5`. Should that be a positive number or a negative number? The specification was written to allow each implementation to make that choice. But of course that creates all sorts of portability issues, which is why truncation towards zero was mandated in C99. – user3386109 Apr 27 '18 at 19:51
  • @YashCatchem It couldn't be 3, because that doesn't satisfy the requirement that `(a/b)*b + a%b=a`. Plugging in the numbers: `(-8/-5)*5 + 3 = -8`. So `(quotient) * 5 = -11`. There's no integer quotient that satisfies that equation. – user3386109 Apr 27 '18 at 20:14
  • @user3386109 "creates all sorts of portability issues" was addressed in C89 by providing `div()`. If code did not want to use the implementation behavior defined `/` or `%`, use `div()`. – chux - Reinstate Monica Apr 27 '18 at 20:34