1

While developing an application I've found a serious error. But first some details: I've wanted to display a temperature on a GUI. The temperature is a double value. The user should be able to increase/decrease the temperature. The goal was to emulate a heating/temperature valve for the heating unit. In addition to have random values, the user should be able to increase/decrease this value by using the GUI. Basically the value is intialized on startup with 20.1 (just a random value I setted at the beginning).

I've noticed a strange behaviour when I tried to decrease the temperature. Everything works finde when incrementing. But decreasing the temperature (by stepsize 1) leads to the following: 20.1 , 19.1 , 18.1, 17.1, 16.1, and then 15.100000000000001, 14.100000000000001 etc.

What's the reason? The error does just occur, when using values ending on .1. So it does make no difference when trying with a base value of 22.1 or 31.1.

The error always occurs with the change from 16.1 to 15...

It's reproducable everytime. I've wrote a test application, feel free to try it:

package devices;

import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Test extends JFrame {

/**
 * the temperature
 */
private Double temp = 20.1;
private JPanel contentPane;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                Test frame = new Test();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the frame.
 */
public Test() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 271, 152);
    contentPane = new JPanel();
    setContentPane(contentPane);
    contentPane.setLayout(null);

    final JLabel lblNewLabel = new JLabel("");
    lblNewLabel.setBounds(10, 11, 235, 56);
    lblNewLabel.setFont(new Font("Tahoma", Font.PLAIN, 19));
    lblNewLabel.setText(String.valueOf(temp));
    contentPane.add(lblNewLabel);

    JButton btnNewButton_1 = new JButton("Increase");
    btnNewButton_1.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            temp = temp + 1;
            lblNewLabel.setText(String.valueOf(temp));
        }
    });
    btnNewButton_1.setBounds(10, 78, 101, 23);
    contentPane.add(btnNewButton_1);

    JButton btnNewButton = new JButton("Decrease");
    btnNewButton.setBounds(137, 78, 108, 23);
    btnNewButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            temp = temp - 1;
            lblNewLabel.setText(String.valueOf(temp));
        }
    });
    contentPane.add(btnNewButton);
}

}

Greetings and thanks in advance,

Julian

3 Answers3

1

0.1 isn't a round number in binary, so you can't always step evenly by tenths. Example here. If tenths are the finest resolution you need, store them as an int and display them manually:

(temp/10).toString() +"."+(tempâ„…10).toString()

This was what Turbo Pascal did for amounts of money, for example.

cxw
  • 16,685
  • 2
  • 45
  • 81
0

Double, and others default float point representations, is a discrete representation for an infinite range os values (between two integers there are infinite values: 1, 1.1, 1.11, 1.11, ... 2).

So, many values don't have a exactly representation.

You should round your number to the precision you need.

Rodolfo
  • 1,091
  • 3
  • 13
  • 35
0

See this

[http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html]

then use BigDecimal instead of Double.

Tuxxy_Thang
  • 179
  • 12