Specifying the number of decimal places

Hi,
I have seen a couple of threads on issues with numbers being returned with a large number of decimal places, in the example case below this seems to be a setpoint ‘feature’

I find it a problem in logs to b e honest where the entry may look something like this

2017-10-20 13:47:29.404 [INFO ] [marthome.model.script.BR1-temp.rules] - Bedroom 1 Temperature: Measured : 20.6 Target: 17.300000000000000710542735760100185871124267578125 Min: 16 State: HOT

The rule that creates this entry is shown below, I have removed a load of stuff not relevant to this thread

rule "bedroom1-temp"
when
Item BR1_Temp received update
then
	// set initial values if undefined
	if (BR1_Max_Temp.state == NULL) postUpdate(BR1_Max_Temp, 19.0)
	if (BR1_Min_Temp.state == NULL) postUpdate(BR1_Min_Temp, 16.0)
	logInfo("BR1-temp.rules", "Bedroom 1 Temperature: Measured : " + BR1_Temp.state + " Target: " + BR1_Tgt_Temp.state + " Min: " + BR1_Min_Temp.state + " State: " + BR1_Temp_State.state)

	// Do not allow temp below regulatory minimum (16C)
	if (BR1_Temp.state < 16 )  {
		if (MQTTBR1Heater_local.state != 1) { // Check if already ON
			MQTTBR1Heater.send(ON)
		}
		if (MQTTBR1Fan_local.state != 0) { // Check if already ON
		MQTTBR1Fan.send(OFF)
		}		
		logInfo("BR1-temp.rules", "Bedroom 1 is considered under temperature, (unhealthy)") 
		if (BR1_Temp_State.state != "UNHEALTHY" ) {
			postUpdate(BR1_Temp_State, "UNHEALTHY")
			sendMail("admin@example.com", "Bedroom 1 climate.", "The temperature has dropped below 16 degrees.")
			logInfo("BR1-temp.rules", "Bedroom 1 email sent, (unhealthy)") 
		}
	}
end

The climate control values such as
BR1_Tgt_Temp
BR1_Max_Temp
BR1_Min_Temp

can be adjusted using the basicUI sitemap with this snip of code

				Frame label="Sleeping Temperature" {
					Setpoint item=BR1_Max_Temp label="Max Temperature [%.1f °C]" icon="temperature" minValue=16 maxValue=35 step=0.1
					Setpoint item=BR1_Tgt_Temp label="Target Temperature [%.1f °C]" icon="temperature" minValue=16 maxValue=30 step=0.1
					Setpoint item=BR1_Min_Temp label="Min Temperature [%.1f °C]" icon="temperature" minValue=16 maxValue=25 step=0.1
					}

Is there a way that I can normalise the value stored in the .state to be formated to a single decimal place?

Alternatively all though not the preferred can we do some trickery in the rule so it displays only one decimal place to the logs?

Thanks

Paul

The most common way to deal with that is to keep the number as is, but when displaying it to the user use formatting (like you already do on the sitemap).
For the display in the log it would need the change code deep in the core of OH and what is of a bigger concern, that would change the display of all values. However other values need to be displayed with all their decimal places. Since this is in the log, which is not the display for the normal user I would not change it there!

Thank you very much for your response.

This seems to be related to setpoint could this be an a feature request
perhaps that setpoint has a parameter that controls the format of the
returned value?

Thats assuming that it is really a setpoint issue. I must confess I do not
understand how a step of 0.1 creates such inaccuracies. I think I will
trywill try some further testing.

afaik you can use formatting for logging:

logInfo("BR1-temp.rules", "Bedroom 1 Temperature: Measured : %1$.1f°C Target: %2$.1f°C Min: %3$.1f°C State: %4$s", BR1_Temp.state,BR1_Tgt_Temp.state ,BR1_Min_Temp.state ,BR1_Temp_State.state)

should (in theory) result in something similar to

2017-10-20 13:47:29.404 [INFO ] [marthome.model.script.BR1-temp.rules] - Bedroom 1 Temperature: Measured : 20.6°C Target: 17.3°C Min: 16.0°C State: HOT

see https://logging.apache.org/log4j/2.x/log4j-users-guide.pdf for reference.

1 Like

This isn’t a setpoint feature. this is a side effect of the fact that computers are really bad at doing floating point math. The way floating point numbers are represented in computers and the way the calculations are performed means that the computer never actually comes up with the exact right answer. It can only get really really close (e.g. 1.099999999999999999 instead of 1.1).

This usually works. It won’t work all the time because see above.

Math::round((MyItem.state as Number * 10).floatValue) / 10

You have to do the same rounding trick illustrated above. Again, this will work some of the time, not all of the time.

You can also use String::format (search the forum for examples) which would let you use the %.1f symbols to round the value for logging.

See above. Computers are just not very good at floating point math. There are all sorts of things you can do but the usual best practice is to leave the floating point results of calculations with all of their decimal places and round them for display to the human.

Thanks Rich for your help.
I am afraid I do not agree that computers are bad at performing floating
point calculations, I would think this is a coding issue.

I have noticed that is if a value is horrendously long if I use setpoint
and add 0.1 and then take it away again returning the value back as it was;
it actually sorts out the issue and becomes the correct value with only one
decimal place. I am wondering if this workaround could be implemented in a
rule somehow.

I will do a search to see if I can find the way to use String::format

Thanks

Paul

In fact, you (or the coder) can do different things to hide some (but not all) wrong results, but the dilemma is, how to represent a potentially infinite floating point number with 32bits (single precision) or 64bits (double precision)?

Well, I have degrees in computer science, spent a whole class on this one topic (Numerical Analysis), and have professionally had to code in scientific computing domains where we needed precision in the millionths place which computers are simply not capable of doing without lots of conversions to integers to do the math.

But what do I know?

https://blog.codinghorror.com/why-do-computers-suck-at-math/

https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

I can supply further links or some references to text books if Wikipedia or my links are not sufficient to convince you.

Indeed. In scientific computing we usually convert the floating points to integers by multiplying to move the decimal place past the precision we need and converting them back to a float at the end or leaving that as an exercise to the student. But I hadve to ask, is it really worth going through all of this extra work for something like the Setpoint in OH? I’d say no and it appears the developers agree.

In fact, it is rarely worth the effort which is why most programs leave them alone and round them when displaying them to a human. Which is what we are suggesting to do here.

1 Like

I am suggesting the rounding is done to the required number of significant
places by the setpoint function.

You may be looking in the wrong place. Have you experimented with different UIs ? I vaguely recall a thread where the setpoint widget(s) gave different results, in terms of 1.1 or 1.099999 etc. Which were transmitted onwards to OH of course.

so is setpoint not part of OH2? I was understanding that this was part of
the openhab application, if not then I can see asking OH to add
functionality to something that is not of the coders doing is a big ask.

I am currently looking into horrendous hacks to step outside of OH2 to fix
the issue which seems a little nuts to me hence why I started the thread.

Thanks

Paul

Yes and no. OH specifies that a sitemap based ui must implement a Setpoint element that can be configured with the set tags. But how it actually gets implemented and presented to the user is some by the client. So in the phone it gets implement by the phone app. In the browser it gets implemented by the JavaScript. That runs in your browser. Which of course means that the behaviors of that simple addition could be different depending on d what browser is used.

I’m not sure what horrendous hacks you are attempting. Using the string formatters in labels and logs is not really a hack when it is THE standard way to manage floating point numbers for human consumption.