Community discussions

MikroTik App
 
changeip
Forum Guru
Forum Guru
Topic Author
Posts: 3830
Joined: Fri May 28, 2004 5:22 pm

Decimals ?

Wed Jun 11, 2008 9:21 pm

Doesn't MT support decimal places ??

[admin@MikroTik] interface> :put (5 / 2)
2

Since when did 5 / 2 = 2 ?

I'm trying to parse the GPS coordinates and convert them back to decimal. Here is a sample script but I cannot get any further since the math is broken.
:global gps [/system gps monitor as-value]

:put ($gps -> "date-and-time")
:put ($gps -> "longitude")

# Parse Longitude
:global long1 [:find ($gps -> "longitude") " " 0]
:global long2 [:find ($gps -> "longitude") " " $long1]
:global long3 [:find ($gps -> "longitude") "'" $long2]
:global long4 [:find ($gps -> "longitude") "''" $long3]

:global degrees [:tonum [:pick ($gps -> "longitude") $long1 $long2 ] ]
:global minutes [:tonum [:pick ($gps -> "longitude") $long2 $long3 ] ]
:global seconds [:tonum [:pick ($gps -> "longitude") ($long3 + 2) $long4 ] ]

:env print

# Should give decimal longitude.
:put ($degrees + ($minutes/60) + ($seconds/3600))

I end up with this:

"gps"={"date-and-time"="jun/11/2008 18:19:25"; "longitude"="W 117 12' 55''"; "latitude"="N 33 13' 49''"; "altitude"="191.399994m"; "speed"="0.111120 km/h"; "valid"=true}
"long1"=1
"long2"=5
"long3"=8
"long4"=12
"degrees"=117
"minutes"=12
"seconds"=55

[master@cip-home] /system gps> :put ($degrees + ($minutes/60) + ($seconds/3600))
117


What happened to my decimals!

If I can get this working I have a script that will upload your routers GPS location to GpsGate.com servers and so you can keep track of your whereabouts on all gps-enabled routers.

Sam
 
User avatar
mrz
MikroTik Support
MikroTik Support
Posts: 7042
Joined: Wed Feb 07, 2007 12:45 pm
Location: Latvia
Contact:

Re: Decimals ?

Wed Jun 11, 2008 11:07 pm

Math is not broken. Router os support only integers.
 
dssmiktik
Forum Veteran
Forum Veteran
Posts: 732
Joined: Fri Aug 17, 2007 8:42 am

Re: Decimals ?

Wed Jul 22, 2009 1:06 am

This will calculate exact decimal values to any decimal places you want. Just plug in dividend, divisor, and decimal places and $result variable will be set to the answer.
# Preforms calculation with decimal points
# dividend / divisor = quotient.decimal = result

:local dividend 3
:local divisor 11
:local decimalplaces 3


# Math Calculation here
:local quotient 0
:local remainder 0
:local result 0
:local decimal 0

:set quotient ($dividend / $divisor)

:if ($quotient = 0) do={
  :set dividend [:tonum ($dividend . "0")]
}

:set remainder ($dividend - ($divisor * $quotient))

:if ($remainder > 0) do={
  :local tmpremainder [:tonum ($remainder . "0")]
  :for x from=1 to=$decimalplaces do={
    :local tmpdecimal [:tonum ($tmpremainder / $divisor)]
    :set decimal [:tonum ($decimal . $tmpdecimal)]
    :set tmpremainder [:tonum (($tmpremainder - ($tmpdecimal * $divisor)) . "0")]
  }
  :set result ($quotient . "." . $decimal)
} else={
  :set result $quotient
}
# END Math Calculation here

:put ($dividend . " / " . $divisor . " = " . $result)

Hope this helps.
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3291
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: Decimals ?

Fri Aug 30, 2019 6:17 pm

Math is not broken. Router os support only integers.
2019 Is this still true?
{
local speed 10
:put $speed
:local speedknots ($speed * 5)
:put $speedknots
}
10
50
{
local speed 10
:put $speed
:local speedknots ($speed * 1.5)
:put $speedknots
}
10
Script Error: cannot multiply time interval by ip prefix
{
local speed 10
:put $speed
:local speedknots ($speed * 1,5)
:put $speedknots
}
10
10;5
 
User avatar
mrz
MikroTik Support
MikroTik Support
Posts: 7042
Joined: Wed Feb 07, 2007 12:45 pm
Location: Latvia
Contact:

Re: Decimals ?

Mon Sep 02, 2019 10:55 am

Yes only integers. Anywhere where you see decimal representation is actually a string.
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3291
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: Decimals ?

Mon Sep 02, 2019 7:43 pm

I know, but MT could add BC or other Linux tool to the script to handle decimal.

Looking forward to v 7.0 :)
 
User avatar
Jotne
Forum Guru
Forum Guru
Posts: 3291
Joined: Sat Dec 24, 2016 11:17 am
Location: Magrathean

Re: Decimals ?

Wed Dec 08, 2021 12:20 pm

Disappointed.
Nothing has changes even when 7.1 is released.
 
User avatar
mrz
MikroTik Support
MikroTik Support
Posts: 7042
Joined: Wed Feb 07, 2007 12:45 pm
Location: Latvia
Contact:

Re: Decimals ?

Wed Dec 08, 2021 2:33 pm

It was never promised that something like that will be implemented in ROSv7.
 
msatter
Forum Guru
Forum Guru
Posts: 2897
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: Decimals ?

Wed Dec 08, 2021 2:48 pm

But users can have hope...

Myself, I multiply values by a number like 10 or 100 or 1000 etc. and then exectute the calculation. Then I can see number of decimals I defined by the multiplication factor, I defined before.

How is this done MTTQ module, there are decimals retrieved from devices are normal?
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3253
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Decimals ?

Fri Dec 10, 2021 7:34 am

It was never promised that something like that will be implemented in ROSv7.

I was told a kernel update get me [:infinity] in v7.∞ someplace too – so disappointing. ;)


But users can have hope...

The more complex solution involves ROS's "ip6" type ( & :toip6 ) – it does have 128-bits available. I'd point you the IETF internet standards here. See RFC8135: Complex Addressing in IPv6 dated April 1, 2017.

Apparently someone thought about what if you had an IPv6 type BUT no "floating point" / "decimal" number type – as is the unusual case on Mikrotik scripts. See Mikrotik's ip6 type could be overload to applying the idea of using IPv6 types for floating points, since it's already longer 128bit int.
  • the "::" can act a decimal place (thus parsable and still somewhat readable being in hex with "::" instead of a more typical "." or ",").
  • negative number could the starting prefix 1000:: (positive) and 1001:: (negative) which non-routable in IPv6 to use a proxy for 1K complement or needing bit arithmetic.
  • some converting to hex and putting ":" every 4 hex chars with the :: separator being int and fractional parts be need to encode a "decimal".
  • Some bits be wasted in this approach. The "::" uses 4 for 0x000 "decimal" separator & another 4 for to store the positive/negative. But these additional bits "wasted" in the "1K-complement prefix" offering expansion to the full set of RFC8135, like imaginary or avian carrier datagrams from RFC1149.
  • the integer part be store in the least significant bits, so 1000:8::4 be +4.1 while 1001:2::8 be -8.2 – searching backward on mikrotik quickly give you the int part this way (I think)


How this theoretically work using Mikrotik's "ip6" type as proxy for a longer int.
:put [$tofloat 0]
                 1000::
:put [$tofloat 1.1]
                   1000:1::1
:put [$tofloat -1.1]
                    1001:1::1
:put [$tofloat 4343.1344]
                         1000:540::10f7


The reverse looks like this:
:put [$fromfloat [$tofloat 0]]
                              0.0
:put [$fromfloat [$tofloat 1.1]]
                                1.1
:put [$fromfloat [$tofloat -1.1]]
                                 -1.1
:put [$fromfloat [$tofloat -123.123]]
                                     -123.123
:put [$fromfloat [$tofloat 4343.1344]]
				4343.1344

Although certainly just multiplying 1000 is easier to proxy decimals is WAY easier. If you needed longer numbers, ip6 type be easier than trying to use an array to store the parts I think. I don't have a need for floating point number in my script – I did the "int shift" way @msattr suggests likely be best. But read this topic and thought of RFC8135.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3253
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Decimals ?

Mon Dec 27, 2021 3:35 am

I was cleaning up some script files, I'd forgotten to publish a partially, buggy implementation of RFC8135 produced that above output.

Basically it uses two functions right now:
$tofloat <str or num> - from a string to a "fakefloat" ( the "ip6" type in ROS)
$fromfloat <ip6> - takes a variable, internally a ip6 type, created by $tofloat to output it as floating/decimal number as string.

There are NO math functions yet, like $ADD <fakefloat>... or $MULTIPLY. And $fromfloat should take an arg like "round=0" to get the integer part or truncate the decimal part. Targeting a 4/1 release for those.

And borrows/adapts the following helpers, which may be more helpful as functions:
$tobase <num> base=[1-32, optional] - used to convert base10 to base16 hexstrings
$strip <string> strip=<char to strip> - used to remove ":" in ip6 addresses.

:global tofloat do={
    :global tobase;
    :local i;
    :local d;
    :local ip6comp 1000
    if ($1~"-") do={
        :set ip6comp 1001
        :set $1 [pick $1 1 99]
    }
    :if ([typeof $1]~("num")) do={
        :set $i $1; 
        :set $d 0;
    } else={ :if ([find $1 "."]>0) do={
        :set i [pick $1 0 [find $1 "."]]
        :set d [pick $1 ([find $1 "."]+1) 64]
        } else={:set $i 0; set $d 0;}
    }
    :local ihex [$tobase $i]
    :local dhex [$tobase $d]
    :local float64 [:toip6 "$ip6comp:$dhex::$ihex"]
    #:put "$ihex $dhex $i $d $float64"
    :return $float64
}

:global fromfloat do={
    :global strip
    :local float64 [tostr $1]
    :local neg ""
    :if ($float64~"1001.+") do={:set $neg "-"}
    :set $float64 [pick $float64 5 64]
    :local ipart [$strip char=":" [pick $float64 ([find $float64 "::"]+2) 64]]
    :local dpart [$strip char=":" [pick $float64 0 ([find $float64 ":"]+1)]]
    #if ([typeof [tonum $dpart]]!="num") do={set dpart 0}
    #:put "$float64 $neg $ipart $dpart"
    :set ipart [tonum "0x$ipart"]
    :set dpart [tonum "0x$dpart"]
    :local strfloat "$neg$ipart.$dpart"
    #:put "$strfloat $ipart $dpart"
    :return $strfloat
}

# adapted from msmater https://forum.mikrotik.com/viewtopic.php?t=160989#p792240
:global strip do={
    :local a [tostr $1]
    :local b $char
    :if ([typeof $b]="nil") do={:set b "-"}
    :while ([find $a $b]) do={
        :set $a ("$[:pick $a 0 ([find $a $b]) ]"."$[:pick $a ([find $a $b]+1) ([:len $a])]")}
    :return $a
}


# adapted from System_Convert-Decimal-BaseX by Randy Graham
# :put [$tobase 32 base=16]
:global tobase do={
    :local decnum $1
    :local basenum ""

    :if ([typeof $base]="nil") do={:local base 16} else={:local base}
    :if ($base>0 and $base<33) do={} else={:set $base 16}
    :local chrtable [:toarray "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f"]
    :local chrtable ($chrtable + [:toarray "g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"])
    :local basedigits 0
    :local basearray
    :local bw
    :local loop 1
    :while ($loop=1 ) do={
            :set bw 0
            :for c from=0 to=$basedigits step=1 do={
            :set bw ($bw*$base)
            :if ($bw=0) do={:set bw 1}
        }
        :set basearray ($basearray + [:toarray $bw])
        :set bw ($decnum/$bw)
        :if ($bw > 0) do={
            :set basedigits ($basedigits+1)
        } else={
            :set loop 0
            :set basedigits ($basedigits-1)
        }
    }
    :local dn $decnum
    :local bpv
    :for c from=$basedigits to=0 do={
        :set bpv ($dn/[:pick $basearray $c])
        :set dn ($dn-([:pick $basearray $c]*$bpv))
        :set basenum "$basenum$[:pick $chrtable $bpv]"
    }
    :return $basenum
}
If you save that to the router as a file called "fakefloat", usage like:
:import fakefloat
:global myfloat [$tofloat -10.1]
:put [$fromfloat $myfloat]
# -10.1
With some tests like this:

:put  "$([$tobase 1]) $([$tobase 10]) $([$tobase 16]) $([$tobase 16 base=32])" 

:put "stripchar $([$strip char=":" "1:1:1:1" ])"

:put [$fromfloat [toip6 "1000:1::1"]]
:put [$fromfloat [toip6 "1001:1::1"]]
:put [$fromfloat [toip6 "1000:10::10"]]
:put [$fromfloat [toip6 "1001:10::10"]]
:put [$fromfloat [:toip6 "1001:03e9::1"]]
:put [$fromfloat [:toip6 "1001:1::03e9"]]
:put [$fromfloat [:toip6 "1000:540::10f7"]]

:put [$tofloat 0]
:put [$tofloat 1.1]
:put [$tofloat -1.1]
:put [$tofloat -123.-123]
:put [$tofloat 4343.1344]

:put [$fromfloat [$tofloat 0]]
:put [$fromfloat [$tofloat 1.1]]
:put [$fromfloat [$tofloat -1.1]]
:put [$fromfloat [$tofloat -123.123]]
:put [$fromfloat [$tofloat 4343.1344]]
* only tested on V7.x

Who is online

Users browsing this forum: No registered users and 17 guests