JDK-4639626 : The % is currently unable to deal with negative numbers properly
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: linux
  • CPU: x86
  • Submitted: 2002-02-19
  • Updated: 2017-05-19
  • Resolved: 2002-02-20
Related Reports
Relates :  
Relates :  
Description

Name: jk109818			Date: 02/19/2002


FULL PRODUCT VERSION :
J2SE 1.3.1 -b24

FULL OPERATING SYSTEM VERSION :
glibc-2.2.4-19.3
Linux (hostname) 2.4.9-6
Distribution RedHat 7.x

ADDITIONAL OPERATING SYSTEMS :
I have also tested this on an UtraSparc 10, and the same
thing happens.



A DESCRIPTION OF THE PROBLEM :
When performing modulo arithmetic on negative numbers the
current output is incorrect.  For example -15%7 is
interpretted as being -1, it should be 6.  Modulo should
never return a negative number.  I probably would not have
ever run into this except for the fact that I have been
asked to write a Java implementation of the Enigma Machine
for a professor.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Simply use System.out.println(-15%7);


EXPECTED VERSUS ACTUAL BEHAVIOR :
I expected to obtain a positive number, by definition a
modulo should always be positive.  Instead a -1 was reurned.

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.lang.*;
import java.io.*;


class Test
{
    public static void main(String args[])throws IOException
    {

	System.out.println("testing the output of -15 mod 7");

	System.out.println(-15%7);

	System.out.println((int)(-15 - Math.floor((double)-15/7)*7));
    }
}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
The work around for this, is to use the actual formula for
finding a modulo.  As follows:  a - floor(a/b) * b.
When doing this however you need to keep in mind that when
doing integer arithmetic that Java truncates during division.
So when you do Math.floor(a/b) with a < 0, you will get the
ceiling of that result.  So the work around code should look
like this.
(int)(a - Math.floor((double)a/b)*b)  this will produce the
floor of a/b when a<0 then cast the result back to an int,
for consistancy.
(Review ID: 139829) 
======================================================================

Comments
PUBLIC COMMENTS Request to have a different definition of integer % operator; the / and % operators in Java work correctly together in one of the possible conventions for / and % with negative integers. Therefore Java's behavior is not a bug.
10-06-2004

EVALUATION The % operator is behaving as specified and as intended; this is not a bug. The / and % operators (div and mod in some languages) must be designed to work in concert so that useful identities hold; in this case so that (a/b)*b + (a%b) = a. Given Java's definition of /, the definition of % on negative values is forced to behave as specified for this relation to be true. In the submitted example, -15/7 is defined to be -2; -2*7 + m = -15 => m == -1. Other languages provide alternative definitions of div and mod that also satisfy such relations; e.g. if integer division rounds towards -infinity (flooring) so that -15/7 would be -3 instead of -2 then -15%7 would be 6, as the bug submitter desires. Different definitions of / and % are useful in different applications. For a fuller discussion of the issue, see the 1999 "Rounding with Div and Mod operators" thread in the comp.compilers newsgroup. The various possible definitions are also compared in Raymond T. Boute's paper "The Euclidean Definition of the Functions div and mod", ACM TOPLAS, 14(2):127-144, April 1992. Closing as "not a bug." ###@###.### 2002-02-19 The % operator is not a modulus operator. It is called the "remainder operator" in the Java Language Specification. ###@###.### 2002-07-09
19-02-2002