JDK-6463999 : We need native floor-based division for integers.
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 5.0
  • Priority: P5
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2006-08-25
  • Updated: 2011-02-16
  • Resolved: 2006-08-25
Related Reports
Duplicate :  
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
Currently, dividing a negative integer by something will truncate the quotient to the integer closest to zero. This is not the way mathematicians define integer division, and with good reason. There are often formulas which work only when floor-based truncation is used. This means the result should be the greatest integer less than or equal to the quotient. So -7/5 would be negative 2 instead of negative one.


JUSTIFICATION :
Many formulas use simple division to reduce a number into a smaller sets of ranges. For example, converting milliseconds to days is done by dividing by 86400000L, the number of milliseconds in a day. 

If I want to determine how many days befor a license expires, I subtract midnight of the expiration date from the current time in milliseconds, and divide by the number of days. This works fine for positive numerators, but, using the java division operator with negative values, it produces results that are off by one:
-5L/86400000L produces zero, when I need it to produce -1. By the mathematician's
definition, AKA floor-based division, -5L/86400000L produces -1, which is correct. This
means the day prior to expiration gets the same result as the day after expiration.

I am NOT suggesting changing the behavior of the division operator, which would not be backward compatible. I am proposing either a new operator (preferred) or a new set of methods in class java.lang.Math which give us floor-based division.

There are currently two methods in Math that do floor- and ceiling-based truncation, but they work on floats and doubles, and I need something that works on integers. Converting the numbers to floating point in order to use the existing methods is slow and clumsy.

For another example, run the test program below. Roll the mouse over the grid to see which cell you are over. Two fields at the top display the results. The first one uses java's division operator, and the second uses floor-based division. As you can see, both formulas are correct for cells with positive coordinates, but only the second one gives the correct results when there is a negative coordinate.

Granted, it's always possible to write a more complicated formula that will produce the correct results, but that produces code that is slower and harder to read, and occasionally raises maintanence issues when later developers don't understand why the code is so complicated. A native floor-based operator or method is a faster and much cleaner solution.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
-3 divided by 5 should produce -1

ACTUAL -
-3 divided by 5 produces 0, the same as 3 divided by 5


---------- BEGIN SOURCE ----------
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;

@SuppressWarnings({"HardCodedStringLiteral", "MagicNumber", "MagicCharacter", "StringConcatenation", "StringContatenationInLoop"})
public class FloorDivisionRFE extends JPanel {
	private static JFrame sMainFrame;
	public static final int gridWidth = 50;
	public static final int gridHeight = 50;
	private JLabel gridLocation = new JLabel("loc");
	private JLabel floorGridLocation = new JLabel("Floor");

	public static void main(String[] args) {
		makeFrame();
	}

	private static void makeFrame() {
		sMainFrame = new JFrame("FloorDivisionRFE");
		sMainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		sMainFrame.getContentPane().setLayout(new BorderLayout());
		sMainFrame.add(new FloorDivisionRFE(), BorderLayout.CENTER);
		sMainFrame.setBounds(10, 10, 600, 325);
		sMainFrame.setVisible(true);
	}

	public FloorDivisionRFE() {
		super(new BorderLayout());
		JPanel view = new JPanel(new GridLayout(0, 1));
		view.add(gridLocation);
		view.add(floorGridLocation);
		sMainFrame.add(view, BorderLayout.NORTH);
		revalidate();
			
		MouseMotionListener ml = new MouseMotionAdapter() {
			@Override
			public void mouseMoved(MouseEvent e) {
				Point pt = e.getPoint();
				int y = pt.y - 2*gridHeight;
				int x = pt.x - 2*gridWidth;

				// this formula produces the wrong answer for negative x & y
				int divRow = y/gridHeight;
				int divCol = x/gridWidth;
				gridLocation.setText("(" + divRow + ',' + divCol + ") [java division operator]");

				// this formula works for negative and positive
				int flrRow = floorDivide(y, gridHeight);
				int flrCol = floorDivide(x, gridWidth);
				floorGridLocation.setText("(" + flrRow + ',' + flrCol + ") [floor-based division]");
//				System.err.println("dividing " + x + "/" + gridWidth + " = " + divCol + ", " + flrCol); // NON-NLS
			}
		};
		addMouseMotionListener(ml);
	}

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		for (int xx =0; xx <getWidth(); xx += gridHeight)
			g.drawLine(xx, 0, xx, getHeight());
		for (int yy=0; yy<getHeight(); yy+= gridWidth)
			g.drawLine(0, yy, getWidth(), yy);
		
		int cellsAcross = getWidth()/gridWidth;
		int cellsDown = getHeight()/gridHeight;
		for (int ii=0; ii<cellsAcross; ++ii) {
			int col=ii-2;
			for (int jj=0; jj<cellsDown; ++jj) {
				int row = jj-2;
				int drawX = ii*gridWidth + 5;
				int drawy = jj*gridHeight + 5 + g.getFontMetrics().getHeight();
				g.drawString(String.valueOf(row) + ',' + col, drawX, drawy);
			}
		}
	}
	
	public int floorDivide(int numerator, int divisor) {
		return numerator < 0? (numerator-divisor+1)/divisor : numerator/divisor;
	}

}

---------- END SOURCE ----------

Comments
EVALUATION At this point, addressing this issue via a new library methods is much more tractable than addressing the issue via defining a new language operator. Closing this bug as a duplicate of a request for the former. See bug 4639626 for a discussion of various possible definitions for division and remainder operations.
25-08-2006