Acknowledged

Cannot Calculate Mod (%) with Doubles

I get an error when I try to calculate a mod with two doubles. There is no error when doing the equivalent calculation with a formula.

var a = 5 as Double;  // or 5d
var b = 2 as Double;  // or 2d
var c = a % b;  // ERROR: Cannot perform operation 'mod' on types '$.Toybox.Lang.Double' and '$.Toybox.Lang.Double'.
var d = a - (Math.floor(a/b)) * b;  // No error

Environment:

Mac OS Sequoia 15.1.1 (24B2091)

Connect IQ SDK 7.4.3

Monkey C Extension 1.1.0

VS Code 1.96.4

----------

EDIT: It appears that it's normal for the mod operator to not work with doubles. I would like to recommend mentioning this in the Reference Guide Arithmetic Operators section along with any other exceptions.

  • A suffix is used for other things too..

    var ba=[0,1]b;         //bytrArray

    var na=[0,1];          //array of numbers

  • Correct, the suffixes are only for numerical literals (made of digits, optional minus sign, and optional decimal point). If you try to use them in other contexts, that will be a syntax error.

    You can use toDouble(), toLong(), etc. with a numerical literal, but it would be more efficient to use the appropriate suffix.

    var a = 5.toDouble(); // this is ok but it may make your code slightly less efficient. "var a = 5d;" would be preferred

    var b = (5 + 10)d; // this is invalid, suffixes such "d" only apply to numerical literals. You could use "5d + 10" or "5 + 10d" if you want. In this case, the value without a suffix will be promoted to Double. (Anytime you use an arithmetic operator such as "+" or "/" on a Double and another numeric value, the other value will be promoted to Double. It's not documented, but I think the promotion hierarchy is Number, Long, Float, Double. Any type that's lower in the hierarchy will be promoted to a type that's higher in the hierarchy when the two types are used together in arithmetic.)

    var c = 8; // Yes, this is a Number

    var d = c.toDouble(); // No, it's not possible to use a suffix after a variable, so c.toDouble() is your only option.

  • Thanks! Are the suffixes typically used only at the ends of actual numbers/digits, and I assume the Lang functions are more appropriate after a variable or formula? For example:

    var a = 5.toDouble()  // unusual notation? use suffix instead?
    var b = (5 + 10)d  // unusual notation? use .toDouble() instead?
    var c = 8  // number
    var d = c.toDouble()  // necessary because "cd" would have a different meaning

  • More examples:

    var a = 5; // Number (no decimal point, and no suffix)
    var b = 5l; // Long (l suffix)
    var c = 5.0; // Float (decimal point, and no suffix)
    var d = 5f; // Float (f suffix)
    var e = 5.0f; // Float (f suffix)
    var f = 5d; // Double (d suffix)
    var g = 5.0d; // Double (d suffix)
  • Yeah, as you've discovered, in Monkey C, mod is only defined for integers (like C), and not also for floating-point types (like Java). I doubt this will change, so your only workaround is to define a helper function with a formula to calculate mod, as in your example.

    One note about your code:

    var a = 5 as Double;
    var b = 2 as Double;

    The type casts "a = 5 as Double" and "b = 2 as Double" don't actually change 5 and 2 into Doubles, they only tell the type checker that those values are Doubles.

    If you remove the type casts, "var c = a % b;" will work fine at runtime (as you may have noticed), since a and b are actually Numbers at runtime, despite the type casts to the contrary.

    The way to actually make those values into Doubles to use the "d" suffix:

    var a = 5d;
    var b = 2d;

    They way to signify that a value is a Float is to either use the "f" suffix and/or include a decimal point.

    var a = 5f;
    var b = 2f;

    or

    var a = 5.0;
    var b = 2.0;

    (The corresponding suffix for Long is "l" - lowercase L).

    If you use any of the above ways to make 5 and 2 into floats/doubles, you will see that a % b will also crash at runtime.

    Imo it's best to avoid unnecessary type casts where possible, as they can be misleading, and at worst, they can lead to runtime errors. For example, the following code would build without errors, but it would crash at runtime:

    var a = 5.0 as Number;
    var b = 2.0 as Number;
    var c = a % b;