Jump to content

Recommended Posts

Two new functions have been added: _FractionPower() and _FractionRoot(). It was interesting to discover that the AutoIt power operator returns -1.#IND for all possible roots of negative numbers. It's a bit strange, but anyway. I have also added a Header and this UDF is just about finished. It is possible to optimize performance, but I'll do that if it becomes a necessity in the future. Anyone wanting to create a version with accuracy greater than two values of up to fifteen digits, or catering for imaginary numbers or irrational roots; go ahead. This is already more than sufficient my purposes.

Edited by czardas

Share this post


Link to post
Share on other sites

There's no such thing as a square root of a negative number. Take for example 16, square root = 4, 4 x 4 = 16. If you had -16 it's theoretical sqrt would be -4, -4 x -4 = 16 (not -16).

http://mathforum.org/library/drmath/view/52613.html


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

There's no such thing as a square root of a negative number. Take for example 16, square root = 4, 4 x 4 = 16. If you had -16 it's theoretical sqrt would be -4, -4 x -4 = 16 (not -16).

http://mathforum.org/library/drmath/view/52613.html

 

 

Yeah, but that only applies to roots which are even, so a cubed root of a negative number returns a real negative result.

Edited by czardas

Share this post


Link to post
Share on other sites

I hadn't thought about going outside the square root method, and you'd be correct only roots divisible by 2 (square root, fourth root, etc.) should give you an invalid answer. Looks like the "^" operator needs to work with negative numbers.


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

I think it ought to. By all means suggest it! I have revised my opinion about this.

My solution was to check validity of the input, before using the power operator with positive values, and then changing the sign back to negative afterwards. Perhaps for reasons of speed, such checks are omitted in preferance for returning -1.#IND, which I assume is meant to indicate negative NaN - whatever that is.

Edited by czardas

Share this post


Link to post
Share on other sites

-1:#IND means indefinite, in other words, AutoIt can't come up with a valid answer for that. People have been complaining about this since at least 2006 from my search of the forums here.

EDIT: BTW, I found this work around that will fix that problem.

MsgBox(4096, "The cube root of -27 is", 0 - (27 ^ (1 / 3)))
Edited by BrewManNH

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

Yes it works. You have to run at least two checks. When the number is negative, the divisor has to be odd. As it happens, there is a problem with these new functions. I'll fix it in a mo.

Edit : Reverted to an earlier version. For some reason I changed it because I thought I had found a bug, now I'm wondering if it really was a bug. I had found a bug. :

Edited by czardas

Share this post


Link to post
Share on other sites

It should be working now. I was confused with the additional effect of the dividend of the root fraction which also affects the sign, depending on whether it is odd or even. I'm a bit tired right now. I'll need to look at this again later.

;

#include 'Fraction.au3'

Local $a1 = _Fraction(-1, 8)
Local $a2 = _Fraction(3, 5)
Local $a3 = _FractionRoot($a1, $a2)

ConsoleWrite($a3[0] / $a3[1] & @LF) ; -0.03125
ConsoleWrite((1 / 8) ^ (5 / 3) *-1 & @LF) ; -0.03125

;


Perhaps this will shed some light on why the power operator behaves the way it does. Interesting read:

http://math.stackexchange.com/questions/317528/how-do-you-compute-negative-numbers-to-fractional-powers

I'm beginning to wonder whether this kind of calculation is suitable for floats. I don't see how it could easily be calculated, or if it would make any sense to do so. If anyone finds any issues with the way I have implemented _FractionPower() or _FractionRoot(), please say how you think it should be different.

Edited by czardas

Share this post


Link to post
Share on other sites

This might be a dumb question, but I'v got a migraine and it's making it hard to think right now.
 
But can I use this simply to replace standard autoit division to return accurate results?
 
And if so, which function would I use?
 
would I just replace say 1567/100 with _Fraction(1567, 100)?

Edited by nullschritt

Share this post


Link to post
Share on other sites

Fractions have two components. The upper dividend and lower divisor. The two numbers are stored as array elements.

#include <Array.au3>
#include 'Fraction.au3'

Local $aArray = _Fraction(1567, 100)
_ArrayDisplay($aArray)

This way you avoid using floats to store the value, which in turn avoids rounding which occurs with floats.

There are different ways you can use the functions.

#include <Array.au3>
#include 'Fraction.au3'

Local $aArray = _Fraction(1567, 100)

$aArray = _FractionAdd($aArray, _Fraction(1)) ; Add 1
_ArrayDisplay($aArray)
Edited by czardas

Share this post


Link to post
Share on other sites

Okay thanks, but once I have the fraction, how do I go about multiplying it by an int without dividing it into it's double value?

Do I NEED to convert the value I want to multiply to a fraction too? (n/1)

And if so how do I convert the output back to a double after?

Edited by nullschritt

Share this post


Link to post
Share on other sites

The mathematical operator functions require array parameters, but it's easy as shown above and below.

#include <Array.au3>
#include 'Fraction.au3'

Local $aArray = _Fraction(1567, 100)
Local $iInt = 17

$aArray = _FractionMultiply($aArray, _Fraction($iInt))
_ArrayDisplay($aArray)

; Convert to a double
ConsoleWrite($aArray[0] / $aArray[1] & @LF)

Bear in mind that accuracy is still limited to two sets of 15 digits. I plan to change this in the future (if it turns out not to be too difficult). Also make sure you read the part about the @extended return value.

Edited by czardas

Share this post


Link to post
Share on other sites

Updated the first post with a new version - requires operator64.au3. Fractions are now made up of two Int-64 values. When internal calculations go out of range, double precision is used to return an approximated fraction. This limits precision to between 15 to 17 digits for both dividend and divisor. It ought to be preferable to approximate fractions using _FractionApproximate() before internal calculations go out of range, but this needs further investigation. I'm not sure if I should try to do this automatically. I think this doesn't need to be any more complicated than it is already.

This is an alpha release: @error and @extended values are likely to change. Currently testing.

Examples:

#include 'Fraction.au3'
#include <Array.au3>

; Example 1
Local $rPi = _Fraction(3141592653589793238, 1000000000000000000)
Local $rFr = $rPi, $iMaxDivisor

Do
    ConsoleWrite($rFr[0] &" / " & $rFr[1] & " =" & @TAB)
    ConsoleWrite(StringTrimRight(StringFormat('%.16e',$rFr[0] / $rFr[1]), 5) & @LF)
    $iMaxDivisor = $rFr[1] -1
    $rFr = _FractionApproximate($rPi, $iMaxDivisor) ; Approximate Pi
Until @error


; Example 2 - corruption test
Local $aSequence, $aReverse

; the following expressions remain within range (only just)
$aSequence = _Reciprocal(_FractionAdd(_FractionMultiply(_FractionSubtract(_FractionPower(_Fraction(2), _Fraction(62)), _Fraction(1)), _Fraction(2)), _Fraction(1)))
_ArrayDisplay($aSequence, 'tiny')

$aReverse = _FractionRoot(_FractionAdd(_FractionDivide(_FractionSubtract(_Reciprocal($aSequence), _Fraction(1)), _Fraction(2)), _Fraction(1)), _Fraction(62))
_ArrayDisplay($aReverse, 'YAY')

; just messin' about ;)

 

Edited by czardas

Share this post


Link to post
Share on other sites

I expect the next few posts will be bug fixes - here's the first - patch added to _FractionApproximate(). Incorporating Int-64 turned out to be tricky.

; out of range array error in _FractionApproximate() ==> triggered by the following expression
_FractionApproximate(_Fraction(4450854863457451063, 3338141282112949374), 3338141282112949373)

From the results of Pi approximation (example 1 from post 33), it would appear that a denominator of 8 digits is adequate to represent 17 digits of a float - that's promising. The difference is not easy to define. I have used a new prefix: $r = rational data type (stored in an array).

Edited by czardas

Share this post


Link to post
Share on other sites

The results of the test in post #20 (posted in February) were not as good as I had hoped. This is the main reason I added Int-64 support. After running a similar test below - the new results are quite revealing. You can observe the degradation of double precision as more and more iterations are introduced. This is followed by a similar degradation affecting the accuracy of _Fraction(), and ultimately both methods go into complete meltdown. Well if it floats float your boat - or perhaps they might just sink your boat. :D

#include 'Fraction.au3'

Global $g_iAPPROXIMATIONS = 0

Local $r3rd = [1, 3], $r2Thirds = [2, 3], $fVal = 1/3, $rFr = $r3rd

For $iIterations = 1 To 85
    $g_iAPPROXIMATIONS = 0
    ; Do
    For $i = 1 to $iIterations
        $fVal *= 2/3
        $fVal += 1/3

        $rFr = _FractionMultiply($rFr, $r2Thirds)
        If @extended Then $g_iAPPROXIMATIONS += 1

        $rFr = _FractionAdd($rFr, $r3rd)
        If @extended Then $g_iAPPROXIMATIONS += 1
    Next

    ; Undo
    For $i = 1 to $iIterations
        $fVal -= 1/3
        $fVal /= 2/3

        $rFr = _FractionSubtract($rFr, $r3rd)
        If @extended Then $g_iAPPROXIMATIONS += 1

        $rFr = _FractionDivide($rFr, $r2Thirds)
        If @extended Then $g_iAPPROXIMATIONS += 1
    Next

    ConsoleWrite('Iterations = ' & $iIterations & @LF _
        & StringFormat('%.16e', $fVal) & " Double Precision" & @LF _
        & StringFormat('%.16e', $rFr[0] / $rFr[1]) & " _Fraction()" & @LF _
        & "Approximations = " & $g_iAPPROXIMATIONS & @LF & @LF)

    If $iIterations = 37 Then ConsoleWrite('>>>> Now things start to get a little strange! <<<<' & @LF & @LF)
    If $iIterations = 85 Then ConsoleWrite('>>>> Melt Down! <<<<' & @LF & @LF)
    ;Sleep(100)
Next

This test reveals an ugly truth about modern computers.

Edited by czardas

Share this post


Link to post
Share on other sites

My original solution to the following question revealed a bug in _FractionMod(). Link: https://www.autoitscript.com/forum/topic/178796-ceiling-in-less-than-whole-number-increments/ The bug turned out to be a missing set of parentheses in _FractionFloor() - nothing wrong with the logic. :phew:

Malkey's posted solution is clearly the best, but doing the same thing using fractions is interesting. I decided to post my original method here (fixed version) as an example of using Fraction.au3. Using _FractionMod() turns out to be more complicated and is unlikely to be a suitable method (this is still a good test). The fact that floats are converted to fractions and vice versa is of no great concern: ideally there would be no conversion and preferably no floats involved at all. However it is necessary to test and compare results against double precision - not for speed, but to verify accuracy and usability. The latest version of this UDF is in the first post.
 

#include 'Fraction.au3'

MsgBox(0, "", _CalibrationCeiling(104.09, 1.04))

Func _CalibrationCeiling($fNumber, $fUnit)
    Local $aNum = _Fraction($fNumber)
    If @error Then Return SetError(1) ; NaN

    Local $aUnit = _Fraction($fUnit)
    If @error Or $aUnit[0] <= 0 Then Return SetError(2) ; bad calibration unit
    Local $aMod = _FractionMod($aNum, $aUnit) ; will be less than a whole unit

    Local $bNegative = _IsFractionNegative($aNum)
    If $bNegative Then $aMod[0] *= -1

    If $aMod[0] Then $aNum = _FractionAdd($aNum, ($bNegative ? $aMod : _FractionSubtract($aUnit, $aMod)))
    If Not IsArray($aNum) Then Return SetError(3) ; most likely cause for this error ==> out of bounds

    Return $aNum[0] / $aNum[1]
EndFunc ; _CalibrationCeiling
Edited by czardas

Share this post


Link to post
Share on other sites
Posted (edited)

New example: Calculate how long would it take to generate all melodies allowable under musical copyright laws.

Requires ArrayWorkshop.au3 and Operator64.au3 - See signature below this post. Fraction.au3 can be found in the first post of this thread.

After a recent discussion, I got curious about how long it would take to generate all musical melodies allowable under musical copyright. Nobody understands musical copyright: how does a judge differentiate between a badly played septuplet and a slightly slower quintuplet (LOL)? One rule that I heard (which may or may not apply internationally) is that a melodic sequence must vary after 11 notes (very vague).

First it is necessary to grasp some basic theory. Durations are expressed as fractions of beats. The most commonly used beat value is 1/4 note (one quarter of a whole note). In the calculation below, quarter note beats are divided into (x8) 32ndNotes, (x7) septuplets, (x6) sextuplets, (x5) quintuplets. For the purpose of this calculation, these values are combined in every way possible to produce 3480 extended durations lasting between 1/32 note and 5 whole notes. I have posted the calculation here to demonstrate the suitability of this UDF for certain types of task. There's probably a simple formula for such a calculation - only I don't know it.

#include-once
#include 'fraction.au3' ; requires operator64.au3
#include 'ArrayWorkshop.au3'

; Brute Force Calculation for the Number of Exit Points Within One Quarter Note
; =============================================================================

; graininess (shortest note) = 32ndNotes (x8), septuplets (x7), sextuplets (x6), quintuplets (x5)

; fractions needed: 1/8, 1/7, 1/6, 1/5
; fractions not needed: 1/4, 1/3, 1/2 because ...
; multiples are generated by the process, eg 1/2 = 3/6

Local $aCombinations[8 *7 *6 *5][2],  $aDuration[2]

Local $iCount = 0

; calculate the number of possible durations between 1/32 and a single whole note.
For $8 = 0 To 7 ; 32ndNotes
    For $7 = 0 To 6 ; septuplets
        For $6 = 0 To 5 ; sextuplets
            For $5 = 0 To 4 ; quintuplets
                ; get sustained note combinations (tied note durations)
                $aDuration = _FractionAdd(_Fraction($5, 5), _FractionAdd(_Fraction($6, 6), _FractionAdd(_Fraction($7, 7), _Fraction($8, 8))))
                If $aDuration[0] > $aDuration[1] Then ; total duration must remain within one beat
                    $aDuration[0] = 0 ; set to zero seconds duration
                    $aDuration[1] = 1
                EndIf
                $aCombinations[$iCount][0] = $aDuration[0]
                $aCombinations[$iCount][1] = $aDuration[1]
                $iCount += 1
            Next
        Next
    Next
Next

; remove any duplicate combinations
_ArrayUniqueXD($aCombinations) ; tests for duplicate (full) rows in 2D

Local $iEndPoints = UBound($aCombinations) -1 ; 174 possible termination points within one quarter note

; 10 seconds is long enough for a singer to maintain a note.
; 10 seconds (longest note) @ 120 bpm (moderato) = 20 beats (sustained limit)

$iEndPoints *= 20 ; simply multiply the number of end points by 20
ConsoleWrite("note end points between a 1/32 note and 5 whole beats = " & $iEndPoints & @LF) ; = 3480

; taking a set of 11 pitched notes and 1 rest, calculate how many melodic sequences exist for the selected set
Local $fMelodies = $iEndPoints ^12
ConsoleWrite("all possible melodic sequences from the 11 note set = " & $fMelodies & @LF) ; = 3.15464814713788e+042

; How long would it take to generate all these melodies?
; A theoretical modern version of Deep Blue would be able to calculate 3 * 10^15 chess positions per second (2016).
; https://chess.stackexchange.com/questions/8117/how-many-positions-per-second-can-a-modern-supercomputer-calculate
; I'm just going to cheat and pretend these speeds are comparable.

Local $fYears = ($fMelodies /3.0e+15) /(60 *60 *24 *356)
ConsoleWrite("time in years to generate all sequences = " & $fYears & @LF) ; = 3.41873888882157e+019

; 34,000,000,000,000,000,000 years :D


Clearly brute force is a waste of time - especially when it would produce mostly arrhythmic rubbish anyway. Also consider the fact that this calculation only represents a subset of 11 pitched notes (pitch range can vary). The true answer is a heck of a lot larger than this.

Edited by czardas

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

  • Similar Content

    • By czardas
      I have hardly any time to write any code recently. Even so, one of the most frustrating problems I, and others like myself, encounter is corruption from floating point innacuracies and integer overflow. I haven't had much time to test this, but the given example works. The method to fix division with whole numbers does not appear to be as complicated as I first anticipated. Divisible integers only!
      Func _WholeNumberDivision($iDividend, $iDivisor) ; Input ranges -9223372036854775807 To 9223372036854775807 If Not (IsInt($iDividend) And IsInt($iDivisor)) Then Return SetError(1, 0, $iDividend / $iDivisor) ; integers only If $iDivisor = 0 Then Return SetError(2, 0, $iDividend / $iDivisor) ; division by zero Local $aDiv = [$iDividend, $iDivisor], _ $iSign = 1 For $i = 0 To 1 If $aDiv[$i] > 0x7FFFFFFFFFFFFFFF Or $aDiv[$i] < 0x8000000000000001 Then Return SetError(3, 0, $iDividend / $iDivisor) ; input range exceeded If VarGetType($aDiv[$i]) = "Double" Then $aDiv[$i] = Number($aDiv[$i], 2) ; convert to Int-64 If $aDiv[$i] < 0 Then ; force positive integers $aDiv[$i] *= -1 $iSign *= -1 ; to add back later EndIf Next If Mod($aDiv[0], $aDiv[1]) Then Return SetError(4, 0, $iDividend / $iDivisor) ; not divisible If $aDiv[0] = 0 Then Return 0 If $aDiv[1] = 1 Then Return $aDiv[0] * $iSign Local $iDivision = Floor($aDiv[0] / $aDiv[1]), $iDifference, $iIntegral While $iDivision * $aDiv[1] > $aDiv[0] ; division is overstated $iDifference = ($aDiv[1] * $iDivision) - $aDiv[0] $iIntegral = Floor($iDifference / $aDiv[1]) ; avoid shooting beyond the target If $iIntegral = 0 Then $iIntegral = 1 ; prevents hanging in an infinite loop $iDivision -= $iIntegral WEnd While $iDivision * $aDiv[1] < $aDiv[0] ; division is understated $iDifference = $aDiv[0] - ($aDiv[1] * $iDivision) $iIntegral = Floor($iDifference / $aDiv[1]) If $iIntegral = 0 Then $iIntegral = 1 ; prevents hanging $iDivision += $iIntegral WEnd Return $iDivision * $iSign EndFunc This function currently works with all int-64 values with one exception - the lowest value 0x8000000000000000, and that's only divisible by powers of 2 anyway.
    • By PhoenixXL
      I use Fractions Always In My Script
      But I never Found a UDF for That
      I made a UDF for Using
      So here I want to Share it
      I Named it MathsEx UDF but I Guess Fraction UDF would be Better

      It Requires Three Funtions Of Array.au3

      Currently Supported Functions

      ; #INDEX# ======================================================================================================================= ; Title .........: MathsEx ; AutoIt Version : 3.2.10++ ; Language ......: English ; Description ...: Functions for Carrying Out More Advanced Mathematical Calculations. ; Author(s) .....: Phoenix XL ; Included.......: Three Functions of Array.au3 i.e. _ArraySort and _ArrayReverse and __ArrayQuickSort1D Requires Array.au3 ; =============================================================================================================================== ; 0xDead=57005...............I just Like The Number :) ; #CURRENT# ===================================================================================================================== ; _Find_GCF ; _Find_LCM ; _Subtract_Fraction ; _Add_Fraction ; _Multiply_Fraction ; _Divide_Fraction ; _Reciprocal ; _Compare_Fraction ; _Quotient ; _Simplify ; _IntegerisNegative ; _IntegerisPositive ; _Get_Denominator ; _Get_Numerator ; _To_Fraction ; _To_Mixed_Fraction ; _Is_Fraction_Improper ; _Is_Fraction_Proper ; _Is_Fraction ; =============================================================================================================================== ; #INTERNAL_USE_ONLY# =========================================================================================================== ; _CheckArray ; _Greatest_Common_Factor ; _Operate_Fraction ; _Set_Sequence ; ===============================================================================================================================
      I havent Included Any Examples Yet
      The Documentation is Enough and Is Very Easy To Implement the Funtions
      Though If any Bug or Problem With The UDF Please Share It

      The UDF is Attached in the Post
      V1.1 = Fixed A Bug

      Regards
      Phoenix XL
      MathsEx V1.1.au3
×
×
  • Create New...