[Feature Request] Allow Decimal Arguments in RM Modulo Arithmetic [C-7 2.3.6.144]

I may need to test this more thoroughly, but as yet I've been unable to budge the target variable mod from its initial value of 0 using a simple Arg1 % Arg2 calculation.

EXPECTED RESULT: 0.15

Could the problem be that Rule Machine doesn't care for decimal arguments (seems doubtful, esp. since they are allowed in Actions > Variable Math)? I sense that something else is going on under the hood.

Any insights I may be missing here?

I don't have the answer... but I'm curious:

  1. How are you reaching the expected result of 0.15?
  2. What are you expecting the percent "%" operator to do, exactly?

As far as I know, the percent operator is used to calculate a remainder from two integers/floats. I do not think it works properly with decimal numbers.

If you change the "%" to "/", which is division, the variable should change to 3.125 (based on the values of arg1 and arg2 in your example). If you change it to a "*" (multiplication), the result should be 4.5. I'm just not sure how you are expecting 0.15 as a result.

In this context, decimals are floats (as opposed to numbers, which RM treats as integers). The % sign (modulo operator) takes two operands and returns the remainder of A mod B. Thus, in my working example, since 1.2 "goes into" 3.75 exactly three times, with 0.15 leftover, that is the expected result.

Maybe we need the Support team to weigh in?

Okay, I understand your logic.
I'm a bit new to groovy, so I don't have my head around much of it yet.
But, if you use this playground link, and try:

println 3.75 % 1.2

You will receive an error.
If you change it to 3 % 2; it outputs the expected 1.

1 Like

I fear you have homed in on the underlying issue, namely a Groovy/Java limitation rather than an implementation problem. Math makes no overt distinction about mod being limited to whole numbers, but most textbook examples seem to.

Thanks for punching all that into the Playground sandbox you found and getting back to me.

1 Like

Yes, of course.
I also found this link, where he discusses something similar.
He touches on the fact it may be a rounding issue?? (scroll down to "Caveats")
And that it may be something specific to Java.

I wasn't sure if it was relevant.. but an interesting read nonetheless.

I'll probably end up modifying my rule to use regular division ( / ), followed by round( ) and then subtraction ( - ) to extract the decimal I need. More steps but reliable.

2 Likes

Agreed! Probably what % was already doing in the background anyways... just getting confused. Always love a little brute force.

IIRC the modulus operation expects that the first number be an integer, the second can be either an integer (gets coerced to float) or a float.

1 Like

Good to know that (and I've seen other Groovy programmers refer to this implementation as the 'remainder' function). Going forward should I file a feature request such that:

(a) the % operator be expanded to accept floats for both operands?

or

(b) RM be tweaked so that it will not permit a decimal variable for arg1?

or (my least favorite)

(c) leave RM as-is by constraining both operands to be of type number?

Playing in my groovy sandbox it appears that it doesn't care if the first value is float or integer, but it can't be bigDecimal. So your request should probably be that the first value be forced to float

2 Likes

Meanwhile, confirmed that RM only completes this operation when both operands are integers, as shown here:

1 Like

Accordingly, I've just updated this topic's title and subcategory to "Feature Request", and officially tagging @bravenel for consideration.

Yeah, for whatever reason BigDecimal throws an error, but Float does not. Next release will have this code:

case "%": result = first.toFloat() % second

2 Likes

Excellent, and much appreciated. Would it be any imposition to have both arguments forced to float for the purpose of computation? My ultimate goal is to have it behave as in OP, namely handle two arbitrary decimal values, producing a decimal result.

I doubt there is any difference for the right operand. Why would there be?

Fair enough. Let's jump this first hurdle and wait to see how things go.

I just tested it, and got an identical result for 3.3 % 1.5:

0.2999999523162842

That should suffice for my purposes (of calculating arbitrary angles and such). Ideally, the resultant in your test run should have been 0.3 but we both know Java and Groovy love to do weird things when rounding. Close enough!!

Actually, this is the nature of floating point arithmetic -- it has nothing to do with Groovy as far as I know.