How does division "/" = work for integer types?
Afficher commentaires plus anciens
In doing some work with integers in R2021A I noticed something relatively strange, namely that if A and B are unsigned integers and A >= B/2, then A/B = 1. Before today, I was not aware of this "rounding". In fact this doesn't quite jive with the documentation. In particular, uint32(1)/uint32(2) gives 1, wheras bitshift(uint32(1),-1) gives 0. Per the documentation https://www.mathworks.com/help/matlab/ref/bitshift.html, a bitshift of -1 should give the same result as dividing by 2. Is this expected behavior? I've attached a screenshot.
Réponse acceptée
Plus de réponses (2)
Steven Lord
le 16 Juin 2021
2 votes
See the "Creating Integer Data" and "Arithmetic Operations on Integer Classes" sections on this documentation page.
uno
le 17 Fév 2023
2 votes
Stumbled on this since I've just encontered the same issue. Totally nuts and I believe should be fixed.
Seems at the moment the solution is to use the idivide() function.
16 commentaires
Thomas Bewley
le 17 Avr 2024
Modifié(e) : Thomas Bewley
le 17 Avr 2024
OMG, totally nuts indeed. You have no idea how many hours I've just wasted because of this bug in Matlab (I'm currently writing subroutines for multiprecision arithmetic on unsigned integers, to make modern 128 bit random number generators in Matlab, dusting off my copy of Knuth volume 2...)
In short, for integers, a/b should absolutely give the integer part of a/b, like C does, rounding towards zero. And, you can calculate rem(a,b) if you also need it.
Anything else (like, by default having / round to the NEAREST integer, instead of rounding TOWARDS ZERO) is indeed, totally nuts. When working with integers, it's just not the behavior you need most of the time.
I have switched my code to use idivide like uno suggested. Makes some ugly code even uglier. :(
Mathworks, please fix this.
PS - The default behavior of idivide() is, "correctly", to round towards zero, as is "natural". Why wouldn't /, when operating on integers, implement the default behavior in idivide()? I believe it absolutely should...
PPS - Here is some minimal code showing this inexplicable discrepency:
a=uint8(7), b=uint8(4), answer1=a/b, answer2=idivide(a,b)
Thomas Bewley
le 17 Avr 2024
BTW, about 15 years ago (?), Matlab changed the definition of ' when applied to complex matrices from transpose to conjugate transpose (ctranspose). Inconvenienced me a bit, because it broke the backwards compatibility with some of my hand-written eigenvalue codes, but it was definitely the right thing to do, because ctranspose is the "natural" behavior for complex matrices 99% of the time. I think / for integers is in a similar situation today. This needs to be fixed [to the default behavior of idivide(a,b)], Matlab will be better off for it in the long run if it is.
Walter Roberson
le 17 Avr 2024
IMHO, the "correct" behaviour for integer division is round towards negative infinity.
Thomas Bewley
le 18 Avr 2024
> IMHO, the "correct" behaviour for integer division is round towards negative infinity.
Walter Roberson - that choice at least fixes the problem for unsigned integers (because, that choice is equivalent to rounding towards zero in this case), so it is a better choice than the flawed behavior that the / operator has for integers today in Matlab (rounding to the nearest integer). Typical major applications specifically requiring self-consistent integer arithmetic include PRNGs, AES block cyphers, RSA encription, Mixed Integer Programming, multiprecision integer arithmetic, etc. Your choice fixes the current problem with the / operator in some of those integer math applications.
However, your opinion is still flawed. The axiom that TylerTK stated in the above thread is the only defensible argument. Integer multiplcation and division drive numbers away from and towards, respectively, the origin (not the negative inf point) on the number line; that is, the origin is the relevant comparison point here, not negative inf.
Put another way, the only way for (-m)/n to equal -(m/n) [take, e.g., m=7 and n=4], which is a very logical requirement for doing self-consistent signed integer math, is for the / operator to round towards zero, not towards minus infinity. (The Mathworks employee who selected rounding towards zero to be the default behavior for idivide must have appreciated this.)
Do you have a similarly fundamental integer math argument that motivates a different conclusion? I truly can not think of one.
The current discrepency between the default behavior for idivide, and for the / operator when acting on integers, is something that requires immediate attention by the Mathworks staff. It will be the source of continued frustration for those attempting integer arithmetic in Matlab until it is fixed. I hope our discussion above helps to hghlight this egregious flaw to Mathworks, and to illustrate clearly for them the only correct (no air quotes) solution.
Walter Roberson
le 18 Avr 2024
I see no reason why (-m)/n and -(m/n) must be the same.
Thomas Bewley
le 18 Avr 2024
Because it is a fundamental identity upon which the consistent foundation for (signed) integer mathematics may be built. This isn't opinion; without a self-consistent foundation, things fall apart in a hurry. See, for example, the following:
Integer Division
Integer division and remainder are defined by the relation A = (A/B)*B + (A rem B), where (A rem B) has the sign of A and an absolute value less than the absolute value of B. Integer division satisfies the identity (−A)/B = −(A/B) = A/(−B).
TylerTK
le 18 Avr 2024
consensus
Walter Roberson
le 18 Avr 2024
"Because it is a fundamental identity upon which the consistent foundation for (signed) integer mathematics may be built. "
No, it is not. -(m/n) is unary negation applied to (m/n) and as such has result the depends upon how m/n works. It is perfectly fine if the result does not match (-m/n)
Thomas Bewley
le 18 Avr 2024
Modifié(e) : Thomas Bewley
le 18 Avr 2024
> -(m/n) is unary negation applied to (m/n) and as such has result the depends upon how m/n works.
Philosophically, -(x) shouldn't depend on how the integer x is computed, that's untenable.
For completeness, the relevant quote from Programming Language Pragmatics (3rd ed) by Michael Scott is given below. It all goes back to Ada (and, presumably, C), which consistently/clearly defined "A/B", as something distinct from "some integer value N", related to mod instead of rem, in the text below. Ada and C far predate Matlab, and truncate towards zero when doing integer division. Is there any logical reason to define integer arithmetic in such a manner that the identity (-A)/B = -(A/B) = A/(-B) is NOT satisfied? You haven't yet articulated one, other than to say it's "perfectly fine", which I don't really see. Losing that identity seems, at the very least, like a nonstandard can of worms that easily leads to very-hard-to-find logic and integer programming errors. Why would Matlab prefer to define the rounding operation done by the / operator for integers differently than Ada and C and Mathematica's QuotientRemainder (and, Matlab's very own default idivide behavior) do, thereby losing this valuable identity? I would really like to know: is there a compelling reason related to integer logic and integer programming? Or is this "just to be different"? Does any other major programming language in existence define the rounding operation done by the / operator for signed integers in a manner different than Ada and C and Mathematica and idivide do (that is, towards zero)? I don't know of any.
PS - For signed integers A and B, rem and mod are defined in Matlab identical to their definition in Ada below (as they should). If / is to be defined in Matlab differently than Ada/C/Mathematica/idivide defines it, as below, I think we're going to need to ask ScienceDirect.com to put an asterisk on their page https://www.sciencedirect.com/topics/computer-science/integer-division advising people that integer division is defined this standard way everywhere except Matlab. That would be a strange request indeed...
Ada provides two “remainder” operators, rem and mod for integer types, defined as follows [Ame83, Sec. 4.5.5]:
Integer division and remainder are defined by the relation A = (A/B)*B + (A rem B), where (A rem B) has the sign of A and an absolute value less than the absolute value of B. Integer division satisfies the identity (-A)/B = -(A/B) = A/(-B).
The result of the modulus operation is such that (A mod B) has the sign of B and an absolute value less than the absolute value of B; in addition, for some integer value N, this result must satisfy the relation A = B*N + (A mod B).
See also the consistent behavior in Wolfram Alpha here:
Walter Roberson
le 18 Avr 2024
MATLAB:
"The software was disclosed to the public for the first time in February 1979 at the Naval Postgraduate School in California"
Ada:
"Ada was originally designed by a team led by French computer scientist Jean Ichbiah of Honeywell under contract to the United States Department of Defense (DoD) from 1977 to 1983 to supersede over 450 programming languages used by the DoD at that time"
So Ada is after MATLAB, contrary to your claim that "Ada and C far predate Matlab"
Thomas Bewley
le 18 Avr 2024
Modifié(e) : Thomas Bewley
le 18 Avr 2024
I stand corrected, and retract my use of the word "far".
Indeed, Wikipedia states that Matlab "was first released as a commercial product in 1984". "By the end of the 1980s, several hundred copies had been sold." According to Wikipedia, "early versions" (like, in 1979) were (apparently) "simple matrix calculators with 71 pre-built functions". Also given that, in the 1980s, Matlab was programmed in C, I am highly doubtful that Matlab redefined the / operation for integer operations in a manner fundamentally inconsistent with C (and, Ada), at a time when Matlab was apparently more focused on real and complex Matrix functions like eigen decompositions and riccati equations. Perhaps you know otherwise? Please enlighten me if so.
Anyway, I'm not sure where you are going with this as your response. Does the date of Matlab's early origins, as a matrix calculator, in your mind better justify the current inconsistency of (a) Matlab's defintion of the / operator for both unsigned and signed integers, with (b) the accepted definition that
"Integer division and remainder are defined by the relation A = (A/B)*B + (A rem B), where (A rem B) has the sign of A and an absolute value less than the absolute value of B. Integer division satisfies the identity (-A)/B = -(A/B) = A/(-B)."
as cited over the internet and used by every other major programming language that we have identified in this discussion? Mathematica cites something about how ancient Egyptians would write -7/4 as -2 + 1/4... is that the basis for your stated preference on this matter? It seems to me like the handiness of the (-A)/B = -(A/B) = A/(-B) identity in integer logic would far outweight that historical anecdote.
Walter Roberson
le 18 Avr 2024
"Also given that, in the 1980s, Matlab was programmed in C"
It was programmed in a mix of FORTRAN and C -- heavier on the FORTRAN at the time.
FWIW, the FORTRAN 77 standard (Matlab using FORTRAN 77 at that time) was (still is?):
" 6.1.5 Integer_Division. One operand of type integer may be divided by another operand of type integer. Although the mathematical quotient of two integers is not necessarily an integer, Table 2 specifies that an expression involving the division operator with two operands of type integer is interpreted as an expression of type integer. The result of such a division is called an integer quotient and is obtained as follows: If the magnitude of the mathematical quotient is less than one, the integer quotient is zero. Otherwise, the integer quotient is the integer whose magnitude is the largest integer that does not exceed the magnitude of the mathematical quotient and whose sign is the same as the sign of the mathematical quotient. For example, the value of the expression (-8)/3 is (-2)."
Though, of course, the integer data types in Matlab came much later.
Thomas Bewley
le 19 Avr 2024
Modifié(e) : Thomas Bewley
le 19 Avr 2024
Paul - Yes, Fortran is consistent with C and Ada and all C-like programs that I am aware of (Rust, etc) in this regard. Yet, still inexplicably, in modern Matlab:
>> a=int8(-8); b=int8(3); a/b
ans =
int8
-3
Matlab is apparently the only programming language in the world today which does not do integer division in the standard way: "Integer division and remainder are defined by the relation A = (A/B)*B + (A rem B), where (A rem B) has the sign of A and an absolute value less than the absolute value of B. Integer division satisfies the identity (-A)/B = -(A/B) = A/(-B)."
AFAIK, rereading the above thread, Walter Roberson still hasn't motivated why Matlab implements its nonstandard choice (rounding to the nearest integer), which (I believe it can be reasonably argued) is error-prone due to its failure to satisfy the above stated standard definition, other than to state his preference for yet a third definition (rounding towards negative infinity, which fails to satisfy the above stated identity) as his humble opinion. I request that a committee of persons who are experienced in modern integer programming applications at Mathworks review the arguments laid out in this thread, and come up with a more deliberate path forward.
Let's look at one of the examples you posted:
a=uint8(7);
b=uint8(4);
answer1=a/b
answer2=idivide(a,b)
Would it be useful if a/b were to give the same answer as uint8(double(a)/double(b)), since both a and b are exactly representable in double precision? In other words, should it matter if you convert between double and uint8 before or after performing the division? [This same holds for the six smaller integer types; 64-bit integers have the complication that not all int64 or uint64 values are exactly representable in double precision.]
answer3 = uint8(double(a)/double(b))
answer3b = uint8(7/4)
If we look at a slightly different example:
answer4a = uint8(5/4)
answer4b = uint8(5)/uint8(4)
From the documentation: "If the number being converted to an integer has a fractional part, MATLAB rounds to the nearest integer."
By the way, if you're looking for integer arithmetic in MATLAB (using the operators) to exactly match C's behavior, it doesn't. Integer arithmetic in MATLAB saturates for both signed and unsigned integers instead of wrapping for unsigned integers like C. [And doing a little archaeology as well as remembering some of the discussions, "saturate or wrap" was quite vigorously debated internally when we first introduced integer arithmetic back in 2004 in release R14.]
x = intmax('uint8')
y = x+1 % saturates so y is the same as x, not wrapped to 0
If you're doing image processing on integer image data x, x+1 always being greater than or equal to x is probably a Good Thing.
But if you disagree with the choice of behavior for the backslash operator, you have a solution that you've already identified: use idivide. If I recall correctly, providing C style division was the main motivating factor for its existence!
Graham Cotgreave
le 14 Août 2025
Hoisted by the same bug, wrote and tested a piece of code in C, ported it to Matlab function inside a statechart, took ages to work out the model was failing at some point part way through the simulation. Intial tests resulted in correct answers, (when the result was less than N.5), but failed when the rounding kicked in. All becaus MatLab thinks uint32(1) / uint32(2) is uint32(1) . Thankfully I found this post.
Catégories
En savoir plus sur Characters and Strings dans Centre d'aide et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!