# Calculate With Decimal Numbers - Mikrotik Script RouterOS

    This is a script to do any math operation (+, -, *, and /) with decimal numbers and/or integers in RouterOS. Make sure to copy the text below EXACTLY and paste into a blank Mikrotik script's source. There are no command dependencies, just scripting syntax.

    To use it, it's simply a matter of setting the decimals and decimalop global variables from another script or the console.

    3.x version
    --Doug 06:26, 27 July 2009 (EEST) Update: internally remove leading zeros when calculating

    # Performs operations on decimal numbers
    # This script can be run from command line or other script.
    # To run, set global variables then run this script
    #
    # Global variables (input):
    # decimalop = math operator ( +, -, *, or / )
    # decimalplaces = decimal point places (0 = no decimal point)
    # decimals = string of decimal numbers seperated by spaces (non-negative (-))
    #
    # Global variables (output):
    # decimalresult = result of calculation, "err" if error
    #
    # Example:
    #   add 3 numbers (4.32, 28 and 0.12):
    #        :global decimalop "+"
    #        :global decimals "4.32 28 0.21"
    #        /system script run
    #        :put $decimalresut
    # ### Math Operations ###
    # Do not change this part
    :global decimals
    :global decimalop
    :global decimalplaces
    :global decimalresult "err"
    :local err 0
    :local result ""
    :local divprecision "10"
    :local decimalsarray ""
    # Sanity checks
    :if ([:len $decimalplaces] = 0) do={:set decimalplaces 4} else={
      :for cindex from=0 to=([:len $decimalplaces] - 1) do={
        :local char [:pick $decimalplaces $cindex ($cindex + 1)]
        :if ($char != "0" && $char != "1" && $char != "2" && $char != "3" && $char != "4" && \
              $char != "5" && $char != "6" && $char != "7" && $char != "8" && $char != "9") do={
          :set err ($err + 1)
        }
      }
    }
    :if ($decimalop != "+" && $decimalop != "-" && $decimalop != "*" && $decimalop != "/") do={
      :set err ($err + 1)
    }
    # Check decimals input and convert decimals to array for easier use
    :for d from=0 to=([:len $decimals] - 1) do={
      :local char [:pick $decimals $d ($d + 1)]
      :if ($char = " ") do={
        :set decimalsarray ($decimalsarray . ",")
      } else={
        :if ($char = "." || $char = "0" || $char = "1" || $char = "2" || $char = "3" || $char = "4" || \
           $char = "5" || $char = "6" || $char = "7" || $char = "8" || $char = "9" ) do={
          :set decimalsarray ($decimalsarray . $char)
        } else={:set err ($err + 1)}
      }
    }
    :set decimalsarray [:toarray $decimalsarray]
    :foreach d in=$decimalsarray do={
      :local dps 0
      :for cindex from=0 to=([:len $d] - 1) do={
        :if ([:pick $d $cindex ($cindex + 1)] = ".") do={:set dps ($dps + 1)}
      }
      :if ($dps > 1) do={:set err ($err + 1)}
    }
    # Only preform calculation if no error
    :if ($err = 0) do={
    # Preform calculation from first to last number
        :local cloopindex 0
        :local decimallen 0
        :local curdeclen 0
        :local tmpnum ""
    #   get decimal length for use after calculation
        :foreach d in=$decimalsarray do={
          :local decfound 0
          :for cindex from=0 to=([:len $d] -  1) do={
            :if ([:pick $d $cindex ($cindex + 1)] = ".") do={
              :set curdeclen ([:len $d] - ($cindex + 1))
              :if ($decimalop = "+") do={:if ($curdeclen > $decimallen) do={:set decimallen $curdeclen}}
              :if ($decimalop = "-") do={:if ($curdeclen > $decimallen) do={:set decimallen $curdeclen}}
              :if ($decimalop = "*") do={:set decimallen ($decimallen + $curdeclen)}
              :set decfound 1
            }
          }
          :if ($decfound = 0) do={
            :if ($decimalop = "+") do={:if ($decimallen < 1) do={:set decimallen 1}}
            :if ($decimalop = "-") do={:if ($decimallen < 1) do={:set decimallen 1}}
            :if ($decimalop = "*") do={:set decimallen ($decimallen + 1)}
          }
        }
    #  Loop through decimals from start to finish
        :foreach d in=$decimalsarray do={
          :local decfound 0
          :for cindex from=0 to=([:len $d] -  1) do={
            :if ([:pick $d $cindex ($cindex + 1)] = ".") do={
              :set decfound 1
              :set curdeclen [:len [:pick $d ($cindex + 1) [:len $d]]]
              :set tmpnum ([:pick $d 0 $cindex] . [:pick $d ($cindex + 1) [:len $d]])
            }
          }
          :if ($decfound = 0) do={
            :set curdeclen 1
            :set tmpnum ($d . "0")
          }
    #    Strip leading zeros
            :local zeroindex ([:len $tmpnum] - 1)
            :for cindex from=([:len $tmpnum] - 1) to=0 do={
              :if ($cindex >= 0 && [:pick $tmpnum $cindex ($cindex + 1)] != "0") do={
                :set zeroindex $cindex
              }
            }
            :set tmpnum [:pick $tmpnum $zeroindex [:len $tmpnum]]

    #   Add and Subtract calculation
          :if ($decimalop = "+" || $decimalop = "-") do={

    #     add zeros to decimal
            :if ($curdeclen < $decimallen) do={
              :for cindex from=$curdeclen to=($decimallen - 1) do={
                :set tmpnum ($tmpnum . "0")
              }
            }
            :if ($decimalop = "+") do={
              :if ($decimallen > 0) do={
                :if ($cloopindex = 0) do={:set result $tmpnum} \
                  else={:set result ($result + $tmpnum) }
              }
            }
            :if ($decimalop = "-") do={
              :if ($decimallen > 0) do={
                :if ($cloopindex = 0) do={:set result $tmpnum} \
                  else={:set result ($result - $tmpnum) }
              }
            }
    #   end add and subtract
          }
    #   Multiply calculation
          :if ($decimalop = "*") do={
            :if ($decimallen > 0) do={
              :if ($cloopindex = 0) do={:set result $tmpnum} \
                else={:set result ($result * $tmpnum)}
            }
    #   end multiply
          }
    # Divide calculation
          :if ($decimalop = "/") do={
            :if ($cloopindex = 0) do={:set result $d} else={
    #       calculate decimal point position and strip decimal point from result
              :local resultdecpos 0
              :local resultlen 0
              :local tmpresult ""
    #       Strip out decimal point
              :for cindex from=0 to=([:len $result] - 1) do={
                :if ([:pick $result $cindex ($cindex + 1)] = ".") do={
                  :set resultdecpos $cindex
                } else={:set tmpresult ($tmpresult . [:pick $result $cindex ($cindex + 1)])}
              }
              :set result $tmpresult
              :set resultlen [:len $result]
              :if ($curdeclen > ([:len $result] - $resultdecpos)) do={
                :set resultdecpos 0
    #         add zeros to result
                :for r from=([:len $result] - $resultdecpos) to=$curdeclen do={
                  :set result ($result . "0")
                }
              } else={
                :set resultdecpos ($resultdecpos + $curdeclen)
              }
    #       Strip leading zeros
              :local zeroindex ([:len $result] - 1)
              :for cindex from=([:len $result] - 1) to=0 do={
                :if ($cindex >= 0 && [:pick $result $cindex ($cindex + 1)] != "0") do={
                  :set zeroindex $cindex
                }
              }
              :set result [:pick $result $zeroindex [:len $result]]
              :local decimal ""
              :local dividend $result
              :local divisor $tmpnum
              :local quotient ($dividend / $divisor)
              :local remainder ($dividend - ($divisor * $quotient))

              :if ($remainder > 0) do={
                :local tmpremainder ($remainder . "0")
                :for x from=1 to=$divprecision do={
                  :local tmpdecimal ($tmpremainder / $divisor)
                  :set decimal ($decimal . $tmpdecimal)
                  :set tmpremainder (($tmpremainder - ($tmpdecimal * $divisor)) . "0")
                }
              } else={:set decimal "0"}
             :set result ""
    #       shift decimal point left
              :if (($resultlen - $resultdecpos) > 0) do={
                :if ([:len $quotient] < ($resultlen - $resultdecpos)) do={
                  :for cindex from=[:len $quotient] to=($resultlen - $resultdecpos - 1) do={
                    :set result ("0" . $result)
                  }
                  :set result ("0." . $result . $quotient)
                  :set resultdecpos 1
                } else={
                  :for cindex from=0 to=([:len $quotient]) do={
                    :if ($cindex = ([:len $quotient] - ($resultlen - $resultdecpos))) do={
                      :if ($cindex = 0) do={
                        :set result "0."
                        :set resultdecpos 1
                      } else={
                        :set result ($result . ".")
                        :set resultdecpos $cindex
                      }
                    }
                    :set result ($result . [:pick $quotient $cindex ($cindex + 1)])
                  }
                }
                :set result ($result . $decimal)
    #            :set resultdecpos [:len $result]
              } else={:set result ($quotient . "." . $decimal); :set resultdecpos [:len $quotient]}
              :set decimallen ([:len $result] - $resultdecpos - 1)
    #        if end of array, strip decimal point
              :if ($cloopindex = ([:len $decimalsarray] - 1)) do={
                :local tmpresult ""
                :for cindex from=0 to=([:len $result] - 1) do={
                  :if ([:pick $result $cindex ($cindex + 1)] != ".") do={
                    :set tmpresult ($tmpresult . [:pick $result $cindex ($cindex + 1)])
                  }
                }
                :set result $tmpresult
              }

    #     end cloopindex
            }
    #   end divide
          }
        :set cloopindex ($cloopindex + 1)
    # end d for
        }
    #  Format result, insert decimal point
        :local newresult ""
        :if (([:len $result] - $decimallen) < 0) do={
          :set newresult "0"
          :for r from=[:len $result] to=($decimallen - 1) do={
            :set newresult ($newresult . "0")
          }
          :set result ($newresult . $result)
        }
        :set newresult ""
        :for r from=0 to=(([:len $result] - $decimallen - 1) + $decimalplaces) do={
          :if ($r = ([:len $result] - $decimallen)) do={
            :if ($r = 0) do={:set newresult ($newresult . "0.")}
            :if ($r > 0) do={
              :if ([:pick $result ($r - 1) $r] = "-") do={:set newresult ($newresult . "0")}
              :set newresult ($newresult . ".")
            }
          }
          :if ($r >= [:len $result]) do={:set newresult ($newresult . "0")} else={
            :set newresult ($newresult . [:pick $result $r ($r + 1)])
          }
        }
        :if ([:len $newresult] > 0) do={:set result $newresult}

    #end err check
    }
    # If no errors occurred, set decimalresult to result of calculation
    :if ($err = 0) do={:set decimalresult $result}
    # ### End of Math Operations ###
    Credit: https://wiki.mikrotik.com/wiki/Calculate_with_decimal_numbers