DSL vs Javascript Math

So I am trying to run this equation in openhab, in dsl it all works except needing to have a negative base in an exponential expression. It doesn’t like that, it just returns NaN. My question is, can Javascript actually handle having a negative base? Or can some other scripting language handle that? Supposedly from what I can find Javascript can handle it but I am also having trouble trying to reformat the rule in Javascript, I have yet to mess with it as Rulesdsl has served my purposes well.

    var Number tempf = BigChief_SHT3XTemperature.state as Number
    var Number tempc = (tempf - 32)/1.8
    var Number hum1 = BigChief_SHT3XHumidity.state as Number
    var Number hum2 = hum1/100
    //var Number mathe = -Math.E

    var Number numeratora = -0.0054*tempc
    var Number numeratorb = 2.87+numeratora
    var Number numeratorc = (-Math.E) ** numeratorb.floatValue
    var Number denominator = Math.log(hum2.floatValue)
    var Number numdenom = numeratorc/denominator
    var Number emc = Math.pow(numdenom.floatValue,0.72463768115)
    SoybeanEMC.postUpdate(emc)

Show what you’ve tried.

You can’t just tack a negative sign onto a variable and have it negate that variable. You hacve to multiply by negative one. That’s going to be the case in almost any language, including Rules DSL and JavaScript.

(Math.E * -1)

Ok, this line of code that I commented out I thought returned the negative of Math.E when I sent that directly to the item I am updating to so I figured it was fine.

//var Number mathe = -Math.E

But I will try your suggestion and see where that gets me! That being said the rule still failed once I got the line where I needed to actually make that number the base of the exponential expression.

 var Number numeratorc = (-Math.E) ** numeratorb.floatValue

I tried as written above and below, neither worked. The reasoning for the above solution was that in my reading I found that you could force it to accept the negative base if you wrote it that way, but that may have been for Javascript now that I think about it.

var Number numeratorc = Math.pow(-Math.E, numeratorb.floatvalue```

Well, you didn’t actually do what I said.

This is never going to work, at least not in Rules DSL, it might work in JS.

(-Marth.E)

You need to use

(Math.E * -1)

Trying to recall my high school algebra, but IIRC a negative base in an exponential expression will only work if the exponent is an integer. What physical property are you modeling? Are you sure the expression is not = -1 * (positive number) ** (number)?

Sorry, I haven’t tried it yet. You had asked what I had tried so I was just letting you know what I had already tried, I will try and get it tried out this evening.

Good question, I’ll have to investigate, I’ll try @rlkoshak suggestion and see where that gets me and report back!

So I got some time to try @rlkoshak suggestion, and I’m getting an error, maybe I’m not utilizing it correctly yet.

Type mismatch: cannot convert from Number to double; line 9, column 358, length 5

When I run the rule in this configuration.

var Number tempf = BigChief_SHT3XTemperature.state as Number
    var Number tempc = (tempf - 32)/1.8
    var Number hum1 = BigChief_SHT3XHumidity.state as Number
    var Number hum2 = hum1/100
    var Number mathe = (Math.E * -1)

    var Number numeratora = -0.0054*tempc
    var Number numeratorb = 2.87+numeratora
    var Number numeratorc = Math.pow(mathe, numeratorb.floatValue)



var Number denominator = Math.log(hum2.floatValue)
    var Number numdenom = numeratorc/denominator
    var Number emc = Math.pow(numdenom.floatValue,0.72463768115)
    SoybeanEMC.postUpdate(numeratorc)

This is the line in question that is giving that error in the logs.

var Number numeratorc = Math.pow(mathe, numeratorb.floatValue)

First, don’t try to force the type. Only force the type where it’s necessary and it’s not necessary here.

var tempc = (tempf - 32)/1.8

The Math methods require primitives. mathe is a Number, not a primitive double or float.

var numeratorc = Math.pow(mathe.doubleValue, numeratorb.doubleValue)

You’ve made the call to floatValue everywhere else already. You have to do so here too.

Is there a reason you are not using Units for this? You shouldn’t be converting between units manually.

I thought when I first started I thought I read that it was best not to assign units because it made it easier to deal with them, apparently that’s not actually the case. Maybe that was the case on an older version?

I didn’t call to floatValue on Math because of a misunderstanding on how it works, I thought if the number didn’t change I didn’t need to call floatValue.

That being said, I called floatValue and received another error.

var Number tempf = BigChief_SHT3XTemperature.state as Number
    var Number tempc = (tempf - 32)/1.8
    var Number hum1 = BigChief_SHT3XHumidity.state as Number
    var Number hum2 = hum1/100
    var Number mathe = (Math.E * -1)

    var Number numeratora = -0.0054*tempc
    var Number numeratorb = 2.87+numeratora
    var Number numeratorc = Math.pow(mathe.floatValue, numeratorb.floatValue)



var Number denominator = Math.log(hum2.floatValue)
    var Number numdenom = numeratorc/denominator
    var Number emc = Math.pow(numdenom.floatValue,0.72463768115)
    SoybeanEMC.postUpdate(numeratorc)

And here is the error in logs.

2023-12-19 11:13:50.498 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'SoybeanEMCCalculation' failed: Character N is neither a decimal digit number, decimal point, nor "e" notation exponential mark.

Units have always been useful, particularly when you want one unit and the sensor is giving you a different unit.

In OH 4 you can set the unit metadata on BigCheif_SHT3XTemperature to °C and no matter what the binding is providing the Item will always carry °C. In addition or instead of that in a rule instead of doing the conversion you can use

var tempc = (BigCheif_SHT3XTemperature.state as QuantityType<?>).asUnit('°C.).floatValue

If the Item is already °C you’ll get the state of the Item. If it’s °F, it will convert it to °C for you.

You did change it though. You multiplied it by -1. In Rules DSL the result of all calculations is a BigDecimal which is a Number, not a primitive.

You’ll need to add some logging of the intermediate calculations to narrow it down to a specific line of code that is generating the error and what all the operands on that line are prior to the error.

Ok, I will change that going forward. That is true, I did change that, I’ll clarify, I thought floatValue was for if it was constantly changing, not just if I defined it as a variable and changed it from its original state, but never to change again. I am still getting this error.

2023-12-19 22:04:35.182 [WARN ] [b.core.model.script.actions.BusEvent] - Cannot convert 'NaN' to a state type which item 'SoybeanEMC' accepts: [DecimalType, QuantityType, UnDefType].

With this code.

    var Number tempf = BigChief_SHT3XTemperature.state as Number
    var Number tempc = (tempf - 32)/1.8
    var Number hum1 = BigChief_SHT3XHumidity.state as Number
    var Number hum2 = hum1/100
    var Number mathe = (Math.E * -1)

    var Number numeratora = -0.0054*tempc
    var Number numeratorb = 2.87+numeratora
    var Number numeratorc = Math.pow(mathe.floatValue,numeratorb.floatValue)
   // var Number denominator = Math.log(hum2.floatValue)
    //var Number numdenom = numeratorc/denominator
    //var Number emc = Math.pow(numdenom.floatValue,0.72463768115)
    SoybeanEMC.postUpdate(numeratorc)

I’ve isolated it to this line.

var Number numeratorc = Math.pow(mathe.floatValue,numeratorb.floatValue)

When I run the rule like this, without Math.E being negated, then it runs fine. It’s something to do with having the base being a negative I think.

var Number tempf = BigChief_SHT3XTemperature.state as Number
    var Number tempc = (tempf - 32)/1.8
    var Number hum1 = BigChief_SHT3XHumidity.state as Number
    var Number hum2 = hum1/100
    //var Number mathe = (Math.E * -1)

    var Number numeratora = -0.0054*tempc
    var Number numeratorb = 2.87+numeratora
    var Number numeratorc = Math.pow(Math.E,numeratorb.floatValue)
   // var Number denominator = Math.log(hum2.floatValue)
    //var Number numdenom = numeratorc/denominator
    //var Number emc = Math.pow(numdenom.floatValue,0.72463768115)
    SoybeanEMC.postUpdate(numeratorc)

I should add that numeratorb, which is the exponent of the line that’s giving me trouble, is not a whole number, it varies based on temp but it should always be a decimal. If that makes a difference.

Out of curiosity (I’m retired and like to see if my memory from 50 years ago is still good :wink:) I ran this on an online calculator yesterday (20 C and 70% humidity) with positive base and

got something like 28 and change. Log of number less than one is also negative so numdenom will also be a positive number.

No, how much it is changing has nothing to do with anything. Data in programming have types. Certain operations only work with certain types. Math.pow() only works with primitive double type variables. If you don’t have a double (a Number is not a double) you have to convert it to a double (in this case by calling floatValue).

NaN stands for “Not a Number”. The result of one of your calculations is producing a non-real number as a result.

It sounds like you are hitting one of the documented special cases: Math (Java SE 17 & JDK 17)

That’s why it’s critical when debugging something like this to know the actual values being calculated at each step.

I’m sure your knowledge is still better than mine, I haven’t used this math in at least ten years, so that’s not helping the situation! :joy: I can make it all work fine if I do the calculation on a calculator, it’s just when I take it into RulesDSL that I get the issue. Here are the values I’m getting from each line of my equation with 20c temp and 70% humidity.

    var Number tempf = BigChief_SHT3XTemperature.state as Number
    //var Number tempc = (tempf - 32)/1.8
    var Number tempc = 20
    //var Number hum1 = BigChief_SHT3XHumidity.state as Number
    var Number hum1 = 70
    var Number hum2 = hum1/100
    //var Number mathe = (Math.E * -1)

    var Number numeratora = -0.0054*tempc
    var Number numeratorb = 2.87+numeratora
   // var Number numeratorc = Math.pow(Math.E,numeratorb.floatValue)
   // var Number denominator = Math.log(hum2.floatValue)
    //var Number numdenom = numeratorc/denominator
    //var Number emc = Math.pow(numdenom.floatValue,0.72463768115)
    SoybeanEMC.postUpdate(numeratora)

numeratora = -0.10800000000000001
numeratorb = 2.762

So I do have a positive exponent, with negative Euler’s number as the base, and that’s where things go wrong.

Ok, thank you for clarifying! So I read over that and this is close to what I am running into but not exactly I don’t think, nothing there is quite exactly what I have…

  • If

    • the first argument is negative infinity and the second argument is greater than zero but not a finite odd integer,then the result is positive infinity.

Euler’s number is infinite(and negative in this case), and the exponent(second argument) is 2.762(with 20c as tempc), but when I do this calculation on a calculator I get a negative(presumably)infinite number instead of a positive…

  • If
    • the first argument is negative zero and the second argument is a negative finite odd integer, or
    • the first argument is negative infinity and the second argument is a positive finite odd integer, then the result is negative infinity.

This example is also close, returns negative infinity, but 2.762 wouldn’t be an considered an integer correct?

Unfortunately I know no more than what’s in the JavaDocs.

I’m probably not being clear. You cannot do that and I’m sure that is not what was intended by wherever you found the formula.

Another algebra principle is exponents take priority over multiplication. So do e^2.762, then multiply by -1. It sounds like your calculator has this figured out.

Another option is to multiply both top and bottom by -1, an identity. The -1 goes away on the numerator and the denominator is -1 * log (.7).

That ensures the base nomdenom is also positive. Log (.7) is negative. As to coding that, @rlkoshak is the master of all languages in use by OH.

Lastly log tempc once you start using real data. As number for a number:temperature may return a Rankine value.

Hopefully all that is clear.

That is very possible! I included the equation in question, it is the Modified Halsey equation. I will also try the solution you suggested.