Problem With REMAINDER? 957%60 Be 15 Remainder 57 Not 15 Remainder -3 ?

Home » Asterisk Users » Problem With REMAINDER? 957%60 Be 15 Remainder 57 Not 15 Remainder -3 ?
Asterisk Users 3 Comments

I’m not mathematically gifted, but shouldn’t 957%60 be 15 remainder 57?

Google and my desktop calculator certainly think so.

So where am I going wrong here? The following code

exten => 7,1,Verbose(Context: ${CONTEXT} Exten:${EXTEN})
same => n,Set(myNum

3 thoughts on - Problem With REMAINDER? 957%60 Be 15 Remainder 57 Not 15 Remainder -3 ?

  • All I can tell you is where -3 comes from. From http://www.voip-info.org/wiki/view/Asterisk+Expressions :
    REMAINDER(x,y) computes the remainder of dividing x by y. The return value is x – n*y, where n is the value x/y, rounded to the nearest integer. If this quotient is 1/2, it is rounded to the nearest even number.

    -3 comes from:
    n = x/y = 957/60 = 15.95 which rounds to 16
    n*y = 16*60 = 960
    x – 960 = 957-960 = -3

    I’m not mathematically gifted either but I think the n is the problem. it shouldn’t be the rounded result it should be the integer part of x/y (n)

    Can you just use modulo instead: ${MATH(${myNum}%60,int)}

  • Yes! That’s the one. Thank you. That’s a good workaround.

    The following test dialplan shows the bug (feature?)

    exten => 7,1,Verbose(Context: ${CONTEXT} Exten:${EXTEN})
    same => n,Set(secondsW)
    same => n,While($[${seconds} <= 400]); same => n,Set(minutes=$[FLOOR(${seconds} / 60)])
    same => n,Set(myRemainderSec=$[REMAINDER(${seconds},60)])
    same => n,SET(myModSec=${MATH(${seconds}%60,int)})
    same => n,Verbose(1,Seconds:${seconds} = Minutes:${minutes}
    Remainder Seconds:${myRemainderSec} modulo seconds:${myModSec})
    same => n,Set(seconds=$[${seconds}+3])
    same => n,EndWhile()

    This is the output:

    Seconds:57 = Minutes:0 Remainder Seconds:-3 modulo seconds:57
    Seconds:60 = Minutes:1 Remainder Seconds:0 modulo seconds:0
    Seconds:63 = Minutes:1 Remainder Seconds:3 modulo seconds:3
    Seconds:66 = Minutes:1 Remainder Seconds:6 modulo seconds:6
    Seconds:69 = Minutes:1 Remainder Seconds:9 modulo seconds:9
    Seconds:72 = Minutes:1 Remainder Seconds:12 modulo seconds:12
    Seconds:75 = Minutes:1 Remainder Seconds:15 modulo seconds:15
    Seconds:78 = Minutes:1 Remainder Seconds:18 modulo seconds:18
    Seconds:81 = Minutes:1 Remainder Seconds:21 modulo seconds:21
    Seconds:84 = Minutes:1 Remainder Seconds:24 modulo seconds:24
    Seconds:87 = Minutes:1 Remainder Seconds:27 modulo seconds:27
    Seconds:90 = Minutes:1 Remainder Seconds:-30 modulo seconds:30
    Seconds:93 = Minutes:1 Remainder Seconds:-27 modulo seconds:33
    Seconds:96 = Minutes:1 Remainder Seconds:-24 modulo seconds:36
    Seconds:99 = Minutes:1 Remainder Seconds:-21 modulo seconds:39
    Seconds:102 = Minutes:1 Remainder Seconds:-18 modulo seconds:42
    Seconds:105 = Minutes:1 Remainder Seconds:-15 modulo seconds:45
    Seconds:108 = Minutes:1 Remainder Seconds:-12 modulo seconds:48
    Seconds:111 = Minutes:1 Remainder Seconds:-9 modulo seconds:51
    Seconds:114 = Minutes:1 Remainder Seconds:-6 modulo seconds:54
    Seconds:117 = Minutes:1 Remainder Seconds:-3 modulo seconds:57
    Seconds:120 = Minutes:2 Remainder Seconds:0 modulo seconds:0

    Issue filed at https://issues.asterisk.org/jira/browse/ASTERISK-26493

  • I saw this on the bug list first and sent a reply, but for the archives I’ll copy it here, too.

    REMAINDER() calls libm’s remainder(3) or remainderl(3), infix % calls fmod(3) or fmodl(3).

    remainder(3) is defined to round the quotient to the nearest int (always using round-to-even, notsithstanding the rounding mode), fmod(3) is defined to trunc(3)ate the quotient.

    So the result of x%y will always be in the range [0,x] and the results of remainder(x,y) will be in the range (-y/2,y/2].

    -JimC