NumberConvert.au3 - Jedes System in jedes andere konvertierbar!

  • Hi,

    wie sicher ein paar von euch mitbekommen haben hatte ich vor einer kleinen Weile einen Dezimal- zu Binärumrechner der das Horner-Schema benutzt vorgestellt.
    Dann fiel mir ein, das man so ziemlich alles mit dem Horner-Schema von Dezimalzahlen zu dem Zahlensystem umwandeln kann, wenn man das System geordnet in einem Array anspricht (Source-Code!)
    Nach kurzer Überlegung hab ich mich auch an die Arbeit gemacht und das Script endlich fertig geschrieben!

    Mit NumberConvert.au3 ist es nun möglich:
    Jedes Zahlensystem in jedes andere zu konvertieren und somit nicht mehr auf die einzelnen Funktionen wie z.B. Dec / Hex nutzen zu müssen (auch wenn sie natürlich noch andere Sachen machen.)

    Ich hab zu der UDF noch paar globale und konstante Variablen hinzugefügt die folgendermaßen heißen:

    [autoit]

    Global Const $NS_DEC = "0-1-2-3-4-5-6-7-8-9", _
    $NS_HEX = "0-1-2-3-4-5-6-7-8-9-A-B-C-D-E-F", _
    $NS_BIN = "0-1", _
    $NS_OCT = "0-1-2-3-4-5-6-7", _
    $NS_ABC = "A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z"

    [/autoit]

    Diese dienen dazu um nicht für jedes System ständig die Ziffern / Buchstaben schreiben zu müssen.

    Wenn ihr die Funktion

    [autoit]

    _NumberConvert($sValue, $sNSystemFrom, $sNSystemTo)

    [/autoit]

    aufruft, dann funktioniert das so:

    [autoit]

    _NumberConvert($sValue, $sNSystem1, $sNSystem2)
    ; $sValue ist der Wert / Zahl / Buchstabe den ihr konvertieren möchtet.
    ; $sNSystemFrom ist das Zahlensystem von dem ihr "weg"-konvertieren möchtet.
    ; $sNSystemTo ist das Zahlensystem in das ihr $sValue konvertieren wollt.

    [/autoit]


    Natürlich ist die Funktion langsamer als z.B. Dec / Hex aber sie bietet viele und vorallem individuelle Konvertierungsmöglichkeiten.
    Die Langsamheit der Funktion setzt sich daraus zusammen, das erst von $sNSystemFrom zum Dezimalsystem konvertiert wird und danach vom Dezimalsystem zum $sNSystemTo konvertiert wird.

    Es wird ein Array mit 10.000 Plätzen erstellt, d.h. die maximale Grenze des von und hin Konvertierens liegt bei 10.000.
    Grenze aufgehoben, das Array mit den Plätzen ist jetzt so groß wie die Eingabe wenn ihr die 2. Version ohne Errorhandling nutzt!

    So, kommen wir endlich zur UDF, besser zu den Variablen und der Funktion

    NumberConvert.au3 - Jedes Zahlensystem in jedes andere Konvertieren
    [autoit]

    Global Const $NS_DEC = "0-1-2-3-4-5-6-7-8-9", _
    $NS_HEX = "0-1-2-3-4-5-6-7-8-9-A-B-C-D-E-F", _
    $NS_BIN = "0-1", _
    $NS_OCT = "0-1-2-3-4-5-6-7", _
    $NS_ABC = "A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z"

    [/autoit] [autoit][/autoit] [autoit]

    Func _NumberConvert($sValue, $sNSystemFrom, $sNSystemTo)
    If $sNSystemFrom = $sNSystemTo Then
    Return $sValue
    ElseIf StringInStr($sNSystemFrom, $sValue) = False Then
    Return 0
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $sReturn, $bSign, $iDec, $iToCap, $iExponent = -1, $fTmp

    [/autoit] [autoit][/autoit] [autoit]

    If StringLeft($sValue, 1) = "-" Then
    $bSign = True
    $sValue = StringTrimLeft($sValue, 1)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local Const $S_NS_FROM = StringReplace($sNSystemFrom, "-", ""), _
    $A_NS_FROM = StringSplit($sNSystemFrom, "-", 2), _
    $A_NS_TO = StringSplit($sNSystemTo, "-", 2), _
    $A_VALUE = StringSplit($sValue, "", 2)

    [/autoit] [autoit][/autoit] [autoit]

    Local $A_NS_DEC[10000]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To 9999
    $A_NS_DEC[$i] = $i
    Next

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($A_VALUE) - 1
    $iDec += $A_NS_DEC[StringInStr($S_NS_FROM, $A_VALUE[$i])-1] * UBound($A_NS_FROM) ^ (UBound($A_VALUE) - 1 - $i)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Do
    $sReturn = $A_NS_TO[Mod($iDec, UBound($A_NS_TO))] & $sReturn
    If $iDec / UBound($A_NS_TO) <> Int($iDec / UBound($A_NS_TO)) Then
    $iDec = Int($iDec / UBound($A_NS_TO))
    Else
    $iDec /= UBound($A_NS_TO)
    EndIf
    Until $iDec = 0

    [/autoit] [autoit][/autoit] [autoit]

    If $bSign = True Then $sReturn = "-" & $sReturn

    [/autoit] [autoit][/autoit] [autoit]

    Return $sReturn
    EndFunc

    [/autoit]
    NumberConvert.au3 - Jedes Zahlensystem in jedes andere Konvertieren - ohne Errorhandling aber funktionierend
    [autoit]

    Global Const $NS_DEC = "0-1-2-3-4-5-6-7-8-9", _
    $NS_HEX = "0-1-2-3-4-5-6-7-8-9-A-B-C-D-E-F", _
    $NS_BIN = "0-1", _
    $NS_OCT = "0-1-2-3-4-5-6-7", _
    $NS_ABC = "A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z"

    [/autoit] [autoit][/autoit] [autoit]

    Func _NumberConvert($sValue, $sNSystemFrom, $sNSystemTo)
    If $sNSystemFrom = $sNSystemTo Then
    Return $sValue
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $sReturn, $bSign, $iDec, $iToCap, $iExponent = -1, $fTmp

    [/autoit] [autoit][/autoit] [autoit]

    If StringLeft($sValue, 1) = "-" Then
    $bSign = True
    $sValue = StringTrimLeft($sValue, 1)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local Const $S_NS_FROM = StringReplace($sNSystemFrom, "-", ""), _
    $A_NS_FROM = StringSplit($sNSystemFrom, "-", 2), _
    $A_NS_TO = StringSplit($sNSystemTo, "-", 2), _
    $A_VALUE = StringSplit($sValue, "", 2)

    [/autoit] [autoit][/autoit] [autoit]

    Local $A_NS_DEC[UBound($A_NS_FROM)]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($A_NS_FROM) - 1
    $A_NS_DEC[$i] = $i
    Next

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($A_VALUE) - 1
    $iDec += $A_NS_DEC[StringInStr($S_NS_FROM, $A_VALUE[$i])-1] * UBound($A_NS_FROM) ^ (UBound($A_VALUE) - 1 - $i)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Do
    $sReturn = $A_NS_TO[Mod($iDec, UBound($A_NS_TO))] & $sReturn
    If $iDec / UBound($A_NS_TO) <> Int($iDec / UBound($A_NS_TO)) Then
    $iDec = Int($iDec / UBound($A_NS_TO))
    Else
    $iDec /= UBound($A_NS_TO)
    EndIf
    Until $iDec = 0

    [/autoit] [autoit][/autoit] [autoit]

    If $bSign = True Then $sReturn = "-" & $sReturn

    [/autoit] [autoit][/autoit] [autoit]

    Return $sReturn
    EndFunc

    [/autoit]


    Mache werden sicherlich sagen, ja das gibts doch schon! Ich hab das im Forum xy gesehen oder das hab ich schon lange selbstgemacht!
    Da kann ich nur zustimmen, aber ich möchte es anderen die daran interessiert sind nicht vorenthalten!

    Lob und Kritik sind sehr willkommen und freu mich schon auf euer Feedback! :D

    Die UDF könnt ihr beliebig umbenennen, weil sich #include <NumberConvert ohne Errorhandling.au3> wahrscheinlich nicht so toll ist wie #include <NumberConvert.au3>!

    Wichtig, bitte benutzt die Version ohne Errorhandling ("NumberConvert ohne Errorhandling.au3"), da man dort mehr als nur ein Zeichen konvertieren kann.
    Important, please download the version (2nd) ("NumberConvert ohne Errorhandling.au3") without error handling because it allows you to convert more than one character.

  • hab ich was überlesen, oder vergisst du, dass StringSplit im $result[0] die anzahl der teilstrings zurückgibt
    dann dürften die Schleifen doch eig alle erst bei element 1 beginnen und bis $result[0] durchzählen
    wenn du dann auch noch das array mit $result[0]( oder $result[0]+1, damit du dich nicht um die unterschieldlichen längen kümmern musst) elementen erzeugst, hast du auch das problem mit der begrenzung auf eine länge von 1000 nicht mehr

    MFG inventor

    wenn's weitere Fragen gibt -> PN
    wenn da keine Antwort kommt, überdenk deine Frage noch mal

  • hab ich was überlesen, oder vergisst du, dass StringSplit im $result[0] die anzahl der teilstrings zurückgibt
    dann dürften die Schleifen doch eig alle erst bei element 1 beginnen und bis $result[0] durchzählen
    wenn du dann auch noch das array mit $result[0]( oder $result[0]+1, damit du dich nicht um die unterschieldlichen längen kümmern musst) elementen erzeugst, hast du auch das problem mit der begrenzung auf eine länge von 1000 nicht mehr


    Schau mal genau hin. Er setzt als Flag 2. Damit deaktiviert er die Rückgabe der Anzahl von Elementen in [0]. ;)

    @TE: Kann man sicher mal brauchen :D

    MfG

    There's a joke that C has the speed and efficieny of assembly language combined with readability of....assembly language. In other words, it's just a glorified assembly language. - Teh Interwebz

    C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do, you blow off your whole leg. - Bjarne Stroustrup
    Genie zu sein, bedeutet für mich, alles zu tun, was ich will. - Klaus Kinski

  • ahh, stimmt, ich hab aber grad auch meine brille nicht auf :D

    dann verstehe ich aber immer noch nicht, warum er das macht?
    wär doch viel einfacher und flexibler

    MFG inventor

    wenn's weitere Fragen gibt -> PN
    wenn da keine Antwort kommt, überdenk deine Frage noch mal

  • Hey, dieser Codeschnipsel müsste eigentlich "A" ausgeben. Bekomme aber nur immer "0" heraus geworfen.

    [autoit]

    ConsoleWrite(_NumberConvert('10', $NS_DEC, $NS_HEX) & @CRLF)

    [/autoit]

    Ich erspare mir jetzt die Suche nach der Fehlerquelle, aber ich vermute, dass die Funktion immer nur ein einzelnes Zeichen konvertieren kann? Das bedeutet demnach, dass deine Funktion nicht richtig arbeitet.

  • Zitat

    Das bedeutet demnach, dass deine Funktion nicht richtig arbeitet.

    So ist es, kommentiert man das "Errorhandlling", also die ersten 5 Zeilen in der Funktion aus, funktioniert sie...im 64-Bit-Zahlenraum.

  • Nette Idee, auch wenn ich die Verwendung der globalen Variablen als Speicher für die Zahlensysteme und das riesige Array in der Funktion etwas eigenartig finde.

    Ich hätte das so gemacht (funktioniert nur bis Basis 36):

    Code
    [autoit]

    Func _ConvertNumber($sNumber, $iFrom, $iTo)
    Local Static $sAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    If ($iFrom < 1) Or ($iFrom > 36) Or ($iTo < 1) Or ($iTo > 36) Then
    Return SetError(1, 0, -1)
    EndIf
    If ($iFrom = $iTo) Then Return $sNumber
    Local $i, $iNumber = 0, $sNew = "", $l
    If ($iFrom = 10) Then
    $iNumber = Number($sNumber)
    Else
    ; convert to decimal
    $l = StringLen($sNumber)
    For $i = 1 To $l
    $iNumber += (StringInStr($sAlphabet, StringMid($sNumber, $i, 1)) - 1) * $iFrom^($l - $i)
    Next
    EndIf
    If ($iTo = 10) Then Return $iNumber
    ; convert to the desired base
    Do
    $sNew = StringMid($sAlphabet, Mod($iNumber, $iTo)+1, 1) & $sNew
    $iNumber = Int($iNumber / $iTo)
    Until ($iNumber = 0)
    Return $sNew
    EndFunc

    [/autoit]


    MfG James

  • Erstmal danke ich euch für das tolle Feedback und PainTain das schon erwähnt hat steht im Script das StringSplit mit dem Flag 2, welches im 1. Arrayeintrag [0] keine Arraygröße hinterlässt.
    Bei dem Errorhandling hab ich ein bisschen gepennt, aber ich hab es sofort natürlich ergänzt.

    Die Funktion bietet kein korrektes Error-Handling und ich denke das ist auch nicht nötig, weil ja jeder weiß wie das funktioniert, bzw. kurz in die UDF schauen kann!

    Desweiteren hab ich die Arraygröße von 10000 auf die Größe von $A_VALUE angepasst. D.h. wenn das eingegebene 50 Zeichen lang ist, dann ist der Array auch nur 50 Einträge groß!

  • Auch wenn diese Funktion weniger mit dem mathematischen Hintergrund zutun hat, halte ich sie dennoch für erwähnenswert:

    Spoiler anzeigen
    [autoit]


    Func _TranslateBase($sNumber, $iOldBase = 10, $iNewBase = 2)
    ;by eukalyptus
    If $iOldBase < 2 Or $iOldBase > 128 Or $iNewBase < 2 Or $iNewBase > 128 Then Return SetError(1, 1, False)
    Local $iNum, $aRes, $tChr = DllStructCreate("char[64];")
    If $iOldBase <> 10 Then
    $aRes = DllCall("msvcrt.dll", "uint64:cdecl", "_strtoui64", "str", $sNumber, "ptr", 0, "int", $iOldBase)
    If @error Then Return SetError(1, 2, False)
    $iNum = $aRes[0]
    Else
    $iNum = Int($sNumber)
    EndIf
    $aRes = DllCall("msvcrt.dll", "ptr:cdecl", "_i64toa", "int64", $iNum, "ptr", DllStructGetPtr($tChr), "int", $iNewBase)
    If @error Then Return SetError(1, 3, False)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_TranslateBase

    [/autoit]

    Hat mir schon in einigen Projekten geholfen. Danke eukalyptus! :thumbup:

    lg