Sign in to follow this  
Followers 0
Jentec

Problem with Mod() Funktion

5 posts in this topic

got problems on the funktion Mod() i got alltimes wrong output from this

mod("175367809538821201","1767842701") returns 421042353

but its wrong !?!

real output must be 421042338

why he tel me 421042353 and not 421042338 ?

what its wrong on this script ??

thx for help

Share this post


Link to post
Share on other sites



its ok i use a other way to got the right result

func Mod2($a, $b)
  $c = Int($a / $b)
  $b = $b * $c
  $c = $a - $b
  return $c
EndFunc

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

This looks like a rounding problem. Mod is an integer function, but the numbers you gave are too big for integer (limited to just over 2 billion / 2 thousand-million). The fail-over is use floating-point numbers, but the storage for floating-point is limited and the least significant digits can be lost or scrambled during operations and storage, sort of like rounding off the decimals on a regular number.

Imagine that you are performing some calculations but you can only store 2 digits after the decimal point. This is an example of limited storage that I was talking about earlier.

Determine 500 / 17 * 17 = ?

500 / 17 = 29.41176470588235294118...

Rounding to the nearest 2 digits yields 29.41.

29.41 * 17 = 499.97

So under these circumstances, 500 / 17 * 17 = 499.97, due to rounding error.

The effect gets more noticeable with larger denominators and you are using a pretty big denominator.

The reason the second method, using int and subtraction, worked is that the Int function reset that precision back to 0 as it were. Much easier to work with.

One way to mitigate rounding errors is to see if you can simplify things before asking the computer to perform the calculations. The calculations can be faster and more accurate that way.

Edited by Nutster

David Nuttall
Nuttall Computer Consulting

An Aquarius born during the Age of Aquarius

AutoIt allows me to re-invent the wheel so much faster.

I'm off to write a wizard, a wonderful wizard of odd...

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

got problems on the funktion Mod() i got alltimes wrong output from this

mod("175367809538821201","1767842701") returns 421042353

but its wrong !?!

real output must be 421042338

why he tel me 421042353 and not 421042338 ?

what its wrong on this script ??

thx for help

For the same reason that

mod(175367809538821201,175367809538821200)

gives 32 when you think it should be 1.

The internal precision of numbers is not great enough when dividing and multiplying.

This will work, and could be speeded up I expect

$a = 175367809538821201
$b=1767842701
while $a > $b
    $a -= $b
WEnd
ConsoleWrite($a & @CRLF);mod result

EDIT:

The BigNum udf in example scripts does a much better job.

EDIT AGAIN: I didn't see post #2 until now. That's a much better idea :)

Edited by martin

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Try this:

ConsoleWrite(15 / 175367809538821201 & @LF)

; Result = 8.55345119463298e-017

The floating point format used hits rounding limits at about 15 significant digits. The difference in your answer is below that limit by two digits. You can reduce the introduced error by reducing the scale of the numbers below that limit, too:

Global $iX = 175367809538821201, $iY = 1767842701

ConsoleWrite("Plain Mod():  " & Mod($iX, $iY) & @LF) ; returns 421042353

ConsoleWrite("_MyMod():  " & _MyMod($iX, $iY) & @LF) ; returns 421042338

Func _MyMod($A, $B)
    Local $iScale

    While $B * 2 < $A
        $iScale = $B
        While $iScale * 2 < $A
            $iScale *= 2
        WEnd
        $A -= $iScale
    WEnd

    Return Mod($A, $B)
EndFunc   ;==>_MyMod

:)

Edit: Didn't see Martin's post while testing mine, but this should be faster at reducing the scale.

Edit2: Hmm... I thought that Int() trick in Mod2() above would fail too because of the non-integer parts of the method. But it works just as well as using all integer maths until the last operation.

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0