How to limit Number decimal places

Hello. I am using the following rule,

//////////////////////////////////////////////////////////////////////////////////////////////////
rule “Energy consumption calculation”
//////////////////////////////////////////////////////////////////////////////////////////////////
when
Item Node_garage1 received update
then
var long currentTime = now.millis

if (LastUpdate != 0) {

	var long timeElapsed = currentTime - LastUpdate

if (timeElapsed > 0) {
	var Number power = Node_garage1.state as DecimalType
	var Number energyConsumption = (power * timeElapsed) / 3600000 / 1000 // kWh
	postUpdate(CumulativeEnergyConsumption, CumulativeEnergyConsumption.state as DecimalType + energyConsumption) //increment
	
}
}
LastUpdate = currentTime

end

and the values i’m getting are resulting in some long values… for example when i send a tweet with my current energy value at the end of a day, i get something like this…

49.997096999999999954292206894024275243282318115234375

I understand that i can limit the value in sitemaps, but how can i limit the value to 2 decimal places in the calculations? i would like to limit it as early on as possible to keep things simple, even if it reduces accuracy.

Thanks in advance.

In general you typically don’t round the values until you display it or in this case send it to Twitter. So you will want to round it before sending it off but not during the calculations.

But since you didn’t provide that code where you do that I’ll provide the code for the function you did post. Floating point math accuracy is pretty horrible on computers beyond a certain point (maybe two decimal places) and premature rounding can cause an even faster accumulation of errors. Depending on how often this calculation is done you could be off by several digits.

One way to round is to use the DecimalFormat utility:

val java.text.DecimalFormat df = new java.text.DecimalFormat("#.##")
val Number roundedEnergyConsumption = Double.valueOf(dt.format(CumulativeEnergyConsumption.state as DecimalType + energyConsumption.doubleValue))
postUpdate(CumuativeEnergyConsumption, roundedEnergyConsumption)

Another is to use Math.round, though that is not always guaranteed to work given how computers actually calculate and store floating point numbers. Basically, the divide by 100 at the end may end up reintroducing more than two decimal places again.

val double rounded = java.lang.Math.round(100 * (CumulativeEnergyConsumption.state as DecimalType + energyConsumption))/100.0

Rich

Edited to fix error in DecimalFormat code.

2 Likes

when putting this in my rules file, the openHAB Designer marks this as error:

I am using Java 1.7 on a Raspberry Pi 2

[quote]$java -version
java version “1.7.0_40”
Java™ SE Runtime Environment (build 1.7.0_40-b43)
Java HotSpot™ Client VM (build 24.0-b56, mixed mode)[/quote]

I also included the lib

Any idea?

thanks in advance

Typo on my part. I should have fully qualified the name on both sides of the equals.

Since you are already importing it the easiest fix is:

  1. Change your import to import java.text.DecimalFormat (note the removal of the “.*”)
  2. Change the line to val DecimalFormat df = new DecimalFormat("#.##")

Its hard to get everything right when you are typing from your phone.

Rich

2 Likes

i’m having the same problem but not from a rule file but from handler

I have the same issue, but Openhab Designer does not recognize “Double.valueOf”

Multiple markers at this line

  • Couldn’t resolve reference to JvmIdentifiableElement ‘Double’.
  • Couldn’t resolve reference to JvmIdentifiableElement ‘valueOf’.

Any suggestion I did not see yet?

Static methods and data members are referenced using “::” in the Rules DSL.

Double::valueOf

Thanks, that fixed it :slight_smile: