Sign in to follow this  
Followers 0
andybiochem

Significant Figures UDF

4 posts in this topic

#1 ·  Posted (edited)

[EDIT] Function has now been updated. Works with all numbers I have tried so far. If you find an error, please let me know!

Hi!

I've been meaning to write this UDF for a while, and finally got round to doing it today. A search of the forum returned very little for "significant figures", so I assume this hasn't been done yet.

I guess this can be done much more elegantly using regular expressions etc, but my method seems to be fairly robust.

Please test out the function and let me know if you encounter any major errors.

Note: this whole function would have been sooo much easier if it wasn't for (what I consider to be) an oversight in StringFormat, which I believe is a conversion of stringf in c++? The problem is with padding zeros to the right of a specified width, which apparently:

"If width is prefixed with 0, zeros are added until the minimum width is reached (not useful for left-aligned numbers)."

...I'd LOVE it if I could pad left-aligned numbers!!!!!!

Anyway, here it is in its crappy string manipulated glory (there's some cheeky recursion in there for the recursion-heads!):

;#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <array.au3>

;----- Numbers to test -----
Global $aTest[11][3] = [["Number To Round", "Significant Figures", "Result"], _
        [123456, 14, ""], _
        [123456, 2, ""], _
        [123456, 1, ""], _
        [0.1515, 3, ""], _
        [51.525, 3, ""], _
        [999.9, 2, ""], _
        ["0.000000001245", 3, ""], _
        [-12.231231e15, 12, ""], _
        [1.3456E-13, 3, ""], _
        [-321, 3, ""]]
;
;----- Test Numbers -----
For $i = 1 To 10
    $aTest[$i][2] = _SF($aTest[$i][0], $aTest[$i][1])
Next

_ArrayDisplay($aTest, "")



; #FUNCTION# ;===============================================================================
; Name...........: _SF
; Description ...: Rounds the inputted number to the specified Significant Figures
; Syntax.........: _SF($nNumber[, $iSF = 3])
; Parameters ....: $nNumber - the number to be rounded, can be any AI number style, as a
;                             number or as a string. If sent as a number, the function is
;                             limited to AI specifications.
;                  $iSF - the number of significant figures to round by
; Return values .: Success - Returns the number of SF specified, as a string (intentional)
; Notes .........: Rounding method = "Round Half Away From Zero"
; Author ........: AndyBiochem
; ===========================================================================================
Func _SF($nNumber, $iSF = 3)
    Local $bIsNeg = False, $biDecimal, $aData, $bFoundSF
    Local $iSFCount, $sTemp

    ;----- Check Negative -----
    If StringLeft($nNumber, 1) = "-" Then $bIsNeg = True
    If $bIsNeg Then $nNumber = StringReplace($nNumber, "-", "")
    ;----- Check Form -----
    Switch StringInStr($nNumber, "e")
        Case 0 ;NOT standard form
            ;- strip any leading zeros (not significant) -
            $nNumber = StringReplace($nNumber, "0", " ")
            $nNumber = StringStripWS($nNumber, 1)
            $nNumber = StringReplace($nNumber, " ", "0")
            If StringLeft($nNumber, 1) = "." Then $nNumber = "0" & $nNumber
            ;- get DP if exists & strip out -
            $biDecimal = StringInStr($nNumber, ".")
            $nNumber = StringReplace($nNumber, ".", "")
            ;- Round -
            $nNumber &= " " ;to prevent array-out error
            $aData = StringSplit($nNumber, "")
            $aData[0] = ""
            $bFoundSF = False
            $iSFCount = $iSF
            For $i = 1 To UBound($aData) - 2
                If $aData[$i] <> 0 Then $bFoundSF = True
                If $bFoundSF = False Then ContinueLoop
                ;- denumerate found SF -
                $iSFCount -= 1
                ;- loop until no SF left -
                If $iSFCount > 0 Then ContinueLoop
                ;- round if necessary -
                If $iSFCount = 0 And $aData[$i + 1] >= 5 Then
                    For $j = $i To 0 Step -1
                        $aData[$j] += 1
                        If $aData[$j] = 10 Then
                            $aData[$j] = 0
                        Else
                            ExitLoop ;number not 10 so exit loop
                        EndIf
                    Next
                EndIf
                ;- replace all remaining SF with 0 -
                If $iSFCount < 0 Then $aData[$i] = "0"
            Next
            ;- pick up new data -
            $sTemp = ""
            For $i = 0 To UBound($aData) - 2
                If $i <> 0 And $i = $biDecimal Then $sTemp &= "." ;add . back in
                $sTemp &= $aData[$i]
            Next
            $sTemp = StringStripWS($sTemp, 1) ;removes [0] if "
            ;- add any trailing SFs -
            For $i = 1 To $iSFCount ;$iSFCount will be > 0 if more SFs than digits
                If $i = 1 Then $sTemp &= "."
                $sTemp &= "0"
            Next
            ;- return -
            If $bIsNeg Then $sTemp = "-" & $sTemp
            Return $sTemp
        Case Else ;IS standard form
            ;- try to remove standard form (for +ve e) -
            $nNumber = Number($nNumber)
            ;- test again -
            Switch StringInStr($nNumber, "e")
                Case 0 ;no longer standard form
                    If $bIsNeg Then $nNumber = "-" & $nNumber
                    Return _SF($nNumber, $iSF)
                Case Else ;still standard form; break out
                    $aData = StringSplit($nNumber, "e")
                    $nNumber = StringReplace($aData[1], ".", "")
                    ;- pad zeros -
                    Switch StringInStr($aData[2], "-")
                        Case 0 ;must be positive
                            For $i = 1 To Number($aData[2]) - (StringLen($aData[1]) - 2)
                                $nNumber &= "0"
                            Next
                        Case Else ;must be negative
                            For $i = 1 To Abs(Number($aData[2])) - 1
                                $nNumber = "0" & $nNumber
                            Next
                            $nNumber = "0." & $nNumber
                    EndSwitch
                    ;- recurse as non-standard number -
                    If $bIsNeg Then $nNumber = "-" & $nNumber
                    Return _SF($nNumber, $iSF)
            EndSwitch
    EndSwitch
EndFunc   ;==>_SF
Edited by andybiochem

- Table UDF - create simple data tables - Line Graph UDF GDI+ - quickly create simple line graphs with x and y axes (uses GDI+ with double buffer) - Line Graph UDF - quickly create simple line graphs with x and y axes (uses AI native graphic control) - Barcode Generator Code 128 B C - Create the 1/0 code for barcodes. - WebCam as BarCode Reader - use your webcam to read barcodes - Stereograms!!! - make your own stereograms in AutoIT - Ziggurat Gaussian Distribution RNG - generate random numbers based on normal/gaussian distribution - Box-Muller Gaussian Distribution RNG - generate random numbers based on normal/gaussian distribution - Elastic Radio Buttons - faux-gravity effects in AutoIT (from javascript)- Morse Code Generator - Generate morse code by tapping your spacebar!

Share this post


Link to post
Share on other sites



Please test out the function and let me know if you encounter any major errors...I'm still working on it.

ffs found another. :mellow:

update soon...


- Table UDF - create simple data tables - Line Graph UDF GDI+ - quickly create simple line graphs with x and y axes (uses GDI+ with double buffer) - Line Graph UDF - quickly create simple line graphs with x and y axes (uses AI native graphic control) - Barcode Generator Code 128 B C - Create the 1/0 code for barcodes. - WebCam as BarCode Reader - use your webcam to read barcodes - Stereograms!!! - make your own stereograms in AutoIT - Ziggurat Gaussian Distribution RNG - generate random numbers based on normal/gaussian distribution - Box-Muller Gaussian Distribution RNG - generate random numbers based on normal/gaussian distribution - Elastic Radio Buttons - faux-gravity effects in AutoIT (from javascript)- Morse Code Generator - Generate morse code by tapping your spacebar!

Share this post


Link to post
Share on other sites

heres my function for rounding in all directions, with an option for significant figures.

http://www.autoitscript.com/forum/index.php?showtopic=102686

Yours does look a bit better though :mellow:

Share this post


Link to post
Share on other sites

Function has been update now. Works with all numbers I've thrown at it so far.

This was a complete b*&^%"££ to write :mellow: I thought it'd be easy too.

Please let me know if you find any errors!


- Table UDF - create simple data tables - Line Graph UDF GDI+ - quickly create simple line graphs with x and y axes (uses GDI+ with double buffer) - Line Graph UDF - quickly create simple line graphs with x and y axes (uses AI native graphic control) - Barcode Generator Code 128 B C - Create the 1/0 code for barcodes. - WebCam as BarCode Reader - use your webcam to read barcodes - Stereograms!!! - make your own stereograms in AutoIT - Ziggurat Gaussian Distribution RNG - generate random numbers based on normal/gaussian distribution - Box-Muller Gaussian Distribution RNG - generate random numbers based on normal/gaussian distribution - Elastic Radio Buttons - faux-gravity effects in AutoIT (from javascript)- Morse Code Generator - Generate morse code by tapping your spacebar!

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