; Übliche Exponentialschreibweise ("double"): ; Vorne eine Kommazahl, danach 10^x als Multiplikator ; 9.8765432e10 ; Logarithmische Schreibweise: ("eNumber") ; Vorne das Vorzeichen, [-1, -0, +0, +1], danach 10^x mit x = Kommazahl. ; 9.8765432e10 = 1e10.994604967679 ; Bei extrem großen/kleinen Zahlen wird analog z.B. 1e1e128.0 geschrieben ; Das bedeutet, 1*10^(10^128.0)) ; Vorteile: ; - Wirklich große Zahlen sind möglich: e10000 etc. ist kein Problem ; - Wirklich kleine Zahlen sind möglich: e-10000 etc. ist kein Problem ; Nachteile: ; - Die Genauigkeit ist logischerweise kleiner als bei "double" ; - Rechenoperationen sind in AutoIt geschrieben und dementsprechend langsam ; bzw. fehlerhaft, ich bin nur ein Mensch und kann nicht "alle" Anwendungsfälle testen. Global Const $_EN_RN_LOG10 = Log(10) Global Const $_EN_FPCLASS_QNAN = ["-1.#IND", _EN_eNumber( 0/0)] ; Quiet NaN (warum eigentlich nur negativ?) Global Const $_EN_FPCLASS_NINF = ["-1.#INF", _EN_eNumber(-1/0)] ; Negative infinity Global Const $_EN_FPCLASS_PINF = ["1.#INF" , _EN_eNumber( 1/0)] ; Positive infinity Global Const $_EN_EN_P0 = _EN_eNumber(0.0) Global Const $_EN_EN_N0 = _EN_eNumber(-0.0) Global Const $_EN_EN_1 = _EN_eNumber(1) ; Handhabung ; _EN_eNumber -> erstellt Zahl in log-Schreibweise ; _EN_ToString -> macht daraus einen String ; _EN_ToDouble -> macht daraus ein Double Func _EN_eNumber($x) If IsArray($x) Then Return $x[0] * 10 ^ $x[1] Local $eNum = [$x = 0 ? (1 / $x < 0 ? -0.0 : 0.0) : ($x < 0 ? -1.0 : 1.0), ($x = 0 ? 0 : (Log(Abs($x)) / $_EN_RN_LOG10))] Return $eNum EndFunc Func _EN_ToString($x) If IsArray($x) Then If _EN_IsNaN($x) Then Return $_EN_FPCLASS_QNAN[0] If _EN_IsInf($x) And $x[0] = -1 Then Return $_EN_FPCLASS_NINF[0] If _EN_IsInf($x) And $x[0] = +1 Then Return $_EN_FPCLASS_PINF[0] If (Abs($x[1]) >= 1e12) Or (Abs($x[1]) < 1e-12) Then ; ee notation Local $y = _EN_eNumber($x[1]) Return $x[0] & 'e' & $y[0] & 'e' & $y[1] Else Return $x[0] & 'e' & $x[1] EndIf EndIf Return String($x) EndFunc Func _EN_ToDouble($x) Return IsArray($x) ? $x[0] * 10 ^ $x[1] : Number($x) EndFunc ; Abfragen ; IsNaN - Prüft ob x = NaN ; IsInf - Prüft ob x = -inf oder +inf (beides gibt true zurück) ; Sign - gibt das Vorzeichen zurück, INKLUSIVE +0.0 und -0.0 Func _EN_IsNaN($x) If Not IsArray($x) Then Return $x <> $x Return $x[1] <> $x[1] EndFunc Func _EN_IsInf($x) If Not IsArray($x) Then Return $x = 1e309 Return $x[1] = 1e309 EndFunc Func _EN_Sign($x) If Not IsArray($x) Then If $x <> 0 Then Return $x < 0 ? -1.0 : 1.0 Return 1.0/$x < 0 ? -1.0 : 1.0 EndIf If $x[0] <> 0 Then Return $x[0] Return 1.0/$x[0] < 0 ? -1.0 : 1.0 EndFunc ; Vergleichsoperatoren ; equ -> x = y (tatsächlich implementiert) ; grt -> x > y (tatsächlich implementiert) ; geq -> x >= y (zusammengebaut) ; les -> x < y (zusammengebaut) ; leq -> x <= y (zusammengebaut) Func _EN_Equ($x, $y) ; x = y If Not IsArray($x) Then If Not IsArray($y) Then ; x = Number, y = Number Return $x = $y Else ; x = Number, y = eNum Return $x = _EN_ToDouble($y) EndIf Else If Not IsArray($y) Then ; x = eNum, y = Number Return _EN_ToDouble($x) = $y Else ; x = eNum, y = eNum Return $x[0] = $y[0] And $x[1] = $y[1] EndIf EndIf EndFunc Func _EN_Grt($x, $y) ; x > y If Not IsArray($x) Then If Not IsArray($y) Then ; x = Number, y = Number Return $x > $y Else ; x = Number, y = eNum Return $x > _EN_ToDouble($y) EndIf Else If Not IsArray($y) Then ; x = eNum, y = Number Return _EN_ToDouble($x) > $y Else ; x = eNum, y = eNum If $x[0] = $y[0] Then Return $x[0] > 0 ? $x[1] > $y[1] : $x[1] < $y[1] Else Return $x[0] > $y[0] EndIf EndIf EndIf EndFunc Func _EN_Geq($x, $y) ; x >= y Return _EN_Equ($x, $y) Or _EN_Grt($x, $y) EndFunc Func _EN_Les($x, $y) ; x < y Return Not _EN_Geq($x, $y) EndFunc Func _EN_Leq($x, $y) ; x <= y Return Not _EN_Grt($x, $y) EndFunc ; Primitive mathematische Funktionen ; inc -> return x + 1 (notwendig für addition) ; dec -> return x - 1 (notwendig für subtraktion) ; mul -> return x * y ; div -> return x / y ; add -> return x + y ; sub -> return x - y ; abs -> return absolutwert von x ; neg -> return -x Func _EN_Inc($x) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then Return _EN_eNumber($x + 1) If _EN_IsInf($x) Then Return $x ; Unendlich + 1 = Unendlich Return _EN_eNumber(_EN_ToDouble($x) + 1) EndFunc Func _EN_Dec($x) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then Return _EN_eNumber($x - 1) If _EN_IsInf($x) Then Return $x ; Unendlich - 1 = Unendlich Return _EN_eNumber(_EN_ToDouble($x) - 1) EndFunc Func _EN_Mul($x, $y) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then If Not IsArray($y) Then ; x = Number, y = Number Return _EN_Mul(_EN_eNumber($x), _EN_eNumber($y)) Else ; x = Number, y = eNum Return _EN_Mul(_EN_eNumber($x), $y) EndIf Else If Not IsArray($y) Then ; x = eNum, y = Number Return _EN_Mul($x, _EN_eNumber($y)) Else ; x = eNum, y = eNum If $x[0] = 0 Or $y[0] = 0 Then Return __EN_eNumber(_EN_Sign($x) * _EN_Sign($y) * 0.0, 0) Return __EN_eNumber($x[0] * $y[0], $x[1] + $y[1]) EndIf EndIf EndFunc Func _EN_Div($x, $y) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then If Not IsArray($y) Then ; x = Number, y = Number Return _EN_Div(_EN_eNumber($x), _EN_eNumber($y)) Else ; x = Number, y = eNum Return _EN_Div(_EN_eNumber($x), $y) EndIf Else If Not IsArray($y) Then ; x = eNum, y = Number Return _EN_Div($x, _EN_eNumber($y)) Else ; x = eNum, y = eNum If $x[0] = 0 Then If $y[0] = 0 Then ; 0 / 0 (hier gibt es in AutoIt keine Unterscheidung von -nan und +nan, glaube ich) Return $_EN_FPCLASS_QNAN[1] Else ; 0 / y Return __EN_eNumber(_EN_Sign($x) * _EN_Sign($y) * 0.0, 0) EndIf Else If $y[0] = 0 Then ; x / 0 -> pos or neg inf Return (_EN_Sign($x) * _EN_Sign($y)) > 0 ? $_EN_FPCLASS_PINF[1] : $_EN_FPCLASS_NINF[1] Else ; x / y Return __EN_eNumber($x[0] * $y[0], $x[1] - $y[1]) EndIf EndIf EndIf EndIf EndFunc Func _EN_Add($x, $y) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then If Not IsArray($y) Then ; x = Number, y = Number Return _EN_Add(_EN_eNumber($x), _EN_eNumber($y)) Else ; x = Number, y = eNum Return _EN_Add(_EN_eNumber($x), $y) EndIf Else If Not IsArray($y) Then ; x = eNum, y = Number Return _EN_Add($x, _EN_eNumber($y)) Else ; x = eNum, y = eNum If $x[0] = 0 Then If $y[0] = 0 Then ; 0 + 0 Return _EN_Sign($x) + _EN_Sign($y) < 0 ? $_EN_EN_N0 : $_EN_EN_P0 ; -0.0 + -0.0 = -0.0, sonst 0.0 Else ; 0 + y Return $y EndIf Else If $y[0] = 0 Then ; x + 0 Return $x Else ; x + y Return _EN_Mul(_EN_Inc(_EN_Div($x, $y)), $y) EndIf EndIf EndIf EndIf EndFunc Func _EN_Sub($x, $y) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then If Not IsArray($y) Then ; x = Number, y = Number Return _EN_Sub(_EN_eNumber($x), _EN_eNumber($y)) Else ; x = Number, y = eNum Return _EN_Sub(_EN_eNumber($x), $y) EndIf Else If Not IsArray($y) Then ; x = eNum, y = Number Return _EN_Sub($x, _EN_eNumber($y)) Else ; x = eNum, y = eNum If $x[0] = 0 Then If $y[0] = 0 Then ; 0 - 0 If _EN_Sign($x) < 0 And _EN_Sign($y) > 0 Then Return $_EN_EN_N0 Return $_EN_EN_P0 Else ; 0 - y Return $y EndIf Else If $y[0] = 0 Then ; x - 0 Return $x Else ; x - y Return _EN_Mul(_EN_Dec(_EN_Div($x, $y)), $y) EndIf EndIf EndIf EndIf EndFunc Func _EN_Abs($x) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then Return _EN_Abs(_EN_eNumber($x)) Return __EN_eNumber(Abs($x[0]), $x[1]) EndFunc Func _EN_Neg($x) If Not IsArray($x) Then Return _EN_Neg(_EN_eNumber($x)) Return __EN_eNumber(-$x[0], $x[1]) EndFunc ; Erweiterte mathematische Funktionen 1 ; exp10 -> return 10^x ; log10 -> return logarithmus zur Basis 10 von x ; exp -> return e^x ; log -> return logarithmus zur Basis e von x Func _EN_Exp10($x) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then Return _EN_Exp10(_EN_eNumber($x)) If $x[0] = 0 Then Return $_EN_EN_1 ; 10^0 -> 1 (keine Unterscheidung von +-0.0) If $x[0] < 0 Then Return _EN_Div($_EN_EN_1, __EN_eNumber(1, _EN_ToDouble($x))); 10^-x -> 1/(10^x) Return __EN_eNumber(1, _EN_ToDouble($x)) EndFunc Func _EN_Log10($x) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then Return _EN_Log10(_EN_eNumber($x)) If $x[0] < 0 Then Return $_EN_FPCLASS_QNAN[1] ; x < 0 -> error (nan) If $x[0] = 0 Then Return $_EN_FPCLASS_NINF[1] ; x = 0 -> return -inf Return _EN_eNumber($x[1]) EndFunc Func _EN_Exp($x) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then Return _EN_Exp(_EN_eNumber($x)) If $x[0] = 0 Then Return $_EN_EN_1 ; 10^0 -> 1 (keine Unterscheidung von +-0.0) If $x[0] < 0 Then Return _EN_Div($_EN_EN_1, __EN_eNumber(1, _EN_ToDouble($x))); 10^-x -> 1/(10^x) Return __EN_eNumber(1, _EN_ToDouble($x) / $_EN_RN_LOG10) EndFunc Func _EN_Log($x) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then Return _EN_Log(_EN_eNumber($x)) If $x[0] < 0 Then Return $_EN_FPCLASS_QNAN[1] ; x < 0 -> error (nan) If $x[0] = 0 Then Return $_EN_FPCLASS_NINF[1] ; x = 0 -> return -inf Return _EN_eNumber($x[1] * $_EN_RN_LOG10) EndFunc ; Erweiterte mathematische Funktionen 2 ; sqrt -> return sqrt(x) (nur positiver Teil) ; cbrt -> return cbrt(x) (kann pos oder neg sein) ; pow -> return rationales x^y ; root -> return rationale Wurzel aus x (nur positiver Teil) Func _EN_Sqrt($x) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then Return _EN_Sqrt(_EN_eNumber($x)) If $x[0] < 0 Then Return $_EN_FPCLASS_QNAN[1] If $x[0] = 0 Then Return __EN_eNumber(_EN_Sign($x) * 0, 0) ; es scheint als wäre sqrt(-0.0) = -0.0 If $x[1] = 0 Then Return $_EN_EN_1 Return __EN_eNumber(1, $x[1]/2) EndFunc Func _EN_Cbrt($x) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then Return _EN_Cbrt(_EN_eNumber($x)) If $x[0] = 0 Then Return __EN_eNumber(_EN_Sign($x) * 0, 0) If $x[1] = 0 Then Return __EN_eNumber($x[0], 0) Return __EN_eNumber($x[0], $x[1]/3) EndFunc ; $x beliebig, z.B. 1e500000 ; $y darf maximal "double" Größe haben. Also z.B. 1e50, aber nicht 1e600. Func _EN_Pow($x, $y) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. If Not IsArray($x) Then If Not IsArray($y) Then ; x = Number, y = Number Return _EN_Pow(_EN_eNumber($x), _EN_eNumber($y)) Else ; x = Number, y = eNum Return _EN_Pow(_EN_eNumber($x), $y) EndIf Else If Not IsArray($y) Then ; x = eNum, y = Number Return _EN_Pow($x, _EN_eNumber($y)) Else ; x = eNum, y = eNum If $y[0] = 0 Then Return $_EN_EN_1 ; egal was hoch 0 ist 1 ; rationaler Exponent von negativen Zahlen -> nope. ; AutoIt's x^y schummelt hier und interpretiert y als Integer, wenn die Zahl nah genug an einem ; integer dran ist. Eigentlich macht man das aber nicht so. If $x[0] < 0 Then Return $_EN_FPCLASS_QNAN[1] If $x[0] = 0 Then If $y[0] < 0 Then ; (+-0) ^ -y -> +- inf Return _EN_Sign($x) < 0 ? $_EN_FPCLASS_NINF[1] : $_EN_FPCLASS_PINF[1] Else ; (+-0)^y -> +-0 Return __EN_eNumber(_EN_Sign($x) * 0, 0) EndIf EndIf ; x <> 0 and y <> 0 Return __EN_eNumber($x[0], $x[1]*_EN_ToDouble($y)) ; das ist nicht gut EndIf EndIf EndFunc ; $x beliebig ; 1/$y darf maximal "double" Größe haben. Also z.B. 1e50, aber nicht 1e600. Func _EN_Root($x, $y) ; Rückgabe ist IMMER eine eNumber, Eingaben können auch normale Zahlen sein. Return _EN_Pow($x, _EN_Div($_EN_EN_1, $y)) EndFunc ; Internals Func __EN_eNumber($iSign, $nExponent) Local $eNum = [$iSign, $nExponent] Return $eNum EndFunc