Saturday, November 18, 2017

#1 2013-10-09 06:44:43 am

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Quadratic Equation Solver

Hello.

This script solves quadratic equations, also those with imaginary roots. You may get the coeffecients, and the roots that solves the equation pasted to the clipboard.


Applescript:


property scriptTitle : "Quadratic Equations Solver"
-- Copyright 2013-2015 McUsr: you may use it as you see fit but you must keep this notice.
property cliptextIcon : a reference to file ((path to library folder from system domain as text) & "CoreServices:CoreTypes.bundle:Contents:Resources:ClippingText.icns")
property Debug : false
property listSep : missing value
property basicMessage : missing value


if listSep is missing value then
   set listSep to listSeparator()
   set basicMessage to "Input the coeffecients a " & listSep & "b " & listSep & "c," & return & "in order to solve the equation:" & return & return & "Æ’(x)=ax²+bx+c=0"
end if

set {theMessage, isWarning, l} to {basicMessage, false, {}}
repeat while true
   set l to _LIST_INPUT(theMessage, l as text, isWarning, scriptTitle, false, "regular")
   if length of l is not 3 then
       set isWarning to true
       set theMessage to "I need exactly three coeffecients, that is numbers!" & return & return & theMessage
   else
       set {a, b, c} to l
       exit repeat
   end if
end repeat
# needs three terms
if |abs|(a) < 1.0E-15 then
   if |abs|(b) < 1.0E-15 then
       if |abs|(c) < 1.0E-15 then
           set status to "L ∈ R"
       else
           set status to "L ∈ Ø"
       end if
   else
       set x1 to (-c / b)
       if x1 < 0 then
       else
           set status to "x₁ and xâ‚‚ = " & x1
       end if
   end if
else
   set x1 to (b ^ 2) - 4 * a * c
   # removed bug, thanks to Adam Bell
   if x1 ≥ 0 then
       if b < 0 then
           set x1 to -b + (x1 ^ 0.5)
       else
           set x1 to -b - (x1 ^ 0.5)
       end if
       set x1 to -x1 / 2 / a
       set x2 to c / a / x1
       
       set status to "x₁ = " & x1 & return & "xâ‚‚ = " & x2
       
   else
       set x2 to ((-x1) ^ 0.5) / 2 / a
       set x1 to -b / 2 / a
       if x2 < 0 then set x2 to -x2
       set status to "" & x1 & " ± ί * " & x2
   end if
end if



tell application (path to frontmost application as text)
   if status is in {"L ∈ R", "L ∈ Ø"} then
       display dialog return & status & return with title scriptTitle buttons {"Quit", "Ok"} cancel button 1 default button 2 with icon cliptextIcon giving up after 300
   else
       set btn to button returned of (display dialog return & status & return with title scriptTitle buttons {"Quit", "Clipboard", "Ok"} cancel button 1 default button 3 with icon cliptextIcon giving up after 300)
       if btn = "Clipboard" then set the clipboard to ("a = " & item 1 of l & listSep & " b = " & item 2 of l & listSep & " c = " & item 3 of l & return & "Result: " & status)
   end if
end tell


on listSeparator()
   if text 2 of ((1 / 2) as text) is "," then
       return ";    "
   else
       return ","
   end if
end listSeparator


on _LIST_INPUT(txt, defaAns, isWarning, scriptName, stayAlive, listType)
   -- The core of the handler originally written by Nigel Garvey.
   -- Parameters:
   --            txt:            Text:        The message that is shown in the input dialog.
   --            defaAns:        Text:    The default value that is show in the input field.
   --            isWarning:    Boolean: If set to true, then a caution icon is shown, not
   --                                        a note icon which is default.
   --            ScriptName:    Text:        Dialog box title, not necessarily a script name.
   --            stayAlive:    Boolean: If true the script returns missing value, otherwise
   --                                        dies.
   --            listType:    Word:        Word can be: "Regular", "PositiveDate", "EveryDate"
   --                                        or "Triplet","Hours".        
   -- Returns:
   --            A list with values on success.
   --            Missing value if the user canceled and stayAlive is true.
   --            {""} if the input was bad somehow.
   --            Dies directly if the user cancelled and the stayalive was false.
   --
   --    If you have this handler in a tell block, then you want to wrap
   --    That tell block into a try block to "smooth over" the error number -128 call.
   local inpt, btnList, isNegative, astid, outpt, digits, param, listSep
   -- Thanks to Yvan Koenig for tips on increasing robustness!
   if listType is not in {"Regular", "PositiveDate", "EveryDate", "Triplet", "Hours"} then ¬
       error "Bad value for listType" number 4015
   set inpt to missing value
   # Configures list separator based on decimal separator: ";" <-- "," and "," <-- "."
   # A list separator always works, as do spaces between elements.
   # A "-" works for dates , when dates are restricted to positive dates.
   # A "." works for separatring elements of dates and times too.
   # A "/" works for separating dates.
   # A ":" works for separating hours.
   # A list of regular numbers can only be separated with space and the designated list separator.
   # Counting of the elements happens in the caller of this handler.
   
   if text 2 of ((1 / 2) as text) is "," then
       set listSep to ";"
   else
       set listSep to ","
   end if
   # Appropriate buttons for whether we shall stay alive or not.
   if stayAlive then
       set btnList to {"Cancel", "Ok"}
   else
       set btnList to {"Quit", "Ok"}
   end if
   
   with timeout of (10 * minutes) seconds
       tell application (path to frontmost application as text)
           if isWarning then
               try
                   set inpt to text returned of (display dialog txt default answer defaAns with title scriptName buttons btnList with icon caution cancel button 1 default button 2)
               end try
           else
               try
                   set inpt to text returned of (display dialog txt default answer defaAns with title scriptName buttons btnList with icon note cancel button 1 default button 2)
               end try
           end if
       end tell
   end timeout
   if inpt is missing value then
       if not my Debug and not stayAlive then -- Need to stay alive here, if we are entering the second date.
           error number -128 -- User hit cancel.
       else
           return missing value -- Thanks to Yvan Koenig.
       end if
   end if
   if inpt is "" then return {}
   
   if listType is "Triplet" then
       ignoring white space
           set isNegative to (inpt begins with "-")
       end ignoring
   else if listType is "EveryDate" then
       set isNegative to (inpt contains "-")
   else
       set isNegative to false
   end if
   log "" & inpt
   set astid to AppleScript's text item delimiters
   set titems to {"-", listSep, space}
   if listType is not in {"PositiveDate", "Triplet"} then set titems to rest of titems
   if listType is in {"PositiveDate", "EveryDate"} then set titems to titems & {".", "/"}
   if listType is in {"Triplet", "Hours"} then set end of titems to ":"
   
   set AppleScript's text item delimiters to titems
   if listType is in {"Triplet", "EveryDate"} then
       set outpt to inpt's words
   else
       set outpt to inpt's text items
   end if
   #    set AppleScript's text item delimiters to " "
   #    set inpt to inpt as text
   set AppleScript's text item delimiters to astid
   
   set reslist to {}
   #    set outpt to inpt's words
   set digits to "1234567890"
   repeat with i from 1 to (count outpt)
       set param to item i of outpt
       if param is not "" and (character 1 of param is in digits or character 1 of param is "-") then
           try -- Thanks to Yvan Koenig.
               set param to param as number
           on error
               if listType is not in {"PositiveDate", "EveryDate"} then
                   # Can't have decimal fraction anyway
                   try
                       set AppleScript's text item delimiters to "."
                       set param to text items of param
                       set AppleScript's text item delimiters to ","
                       set param to param as text
                       set AppleScript's text item delimiters to astid
                       set param to param as number
                   on error
                       return {""} -- this must be resolved by caller
                   end try
               else
                   return {""}
               end if
           end try
           if (isNegative) then # This works only for triplets
               if listType is in {"EveryDate", "Triplet"} then set param to -param
           end if
           set end of reslist to param
       end if
   end repeat
   
   return reslist
end _LIST_INPUT

on |abs|(i)
   -- absolute value, faster than from an Osax.
   return i * (-1 + 2 * ((i > 0) as integer))
   -- if i > 0 then we add two, and multiply with 1
   -- if i < 0 then we add zero and multiply with -1
end |abs|

Last edited by McUsrII (2015-06-27 04:02:58 am)

Offline

 

#2 2013-10-09 05:29:18 pm

Adam Bell
Administrator
From:: Nova Scotia, Canada
Registered: 2005-10-04
Posts: 4660

Re: Quadratic Equation Solver

Hi, McUsrII

Three small errors: "if (abs a) < 1.0E-15 then" and those following for "b" and "c" should be of the form:

if abs(a) < 1.0E-15 then

Otherwise, abs is not recognized as a function.


iMac running OS X 10.13.1

Offline

 

#3 2013-10-09 06:13:05 pm

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Re: Quadratic Equation Solver

Hello.

I am sorry for not stating that I used Satimage.osax, because there, abs work like a verb. However, I found another bug, which is now removed, I had taken the square root of a coeffecient, when I should have squared it. hmm

If you have something that uses abs() instead of Satimage's abs, then you are of course right.

Thanks for reporting the bug Adam, I really just made it, and didn't test it extensively enough to reveal it. So it could have taken several days -or longer, before I would have discovered it!

Last edited by McUsrII (2013-10-09 06:18:37 pm)

Offline

 

#4 2013-10-10 10:38:55 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4421

Re: Quadratic Equation Solver

Hi McUsrII.

Your posted script currently contains two copies of the code. Both copies display the wrong signs in the solutions.

Here's my basic effort:

Applescript:

on solveQuad(a, b, c)
   -- ax2 + bx + c = 0. Find the two possible values of x.
   
   if (a = 0) then -- Not quadratic. Return two results anyway.
       set x to {c / -b, c / -b}
   else -- Quadratic.
       set s to b / a / 2
       try
           set r to (s ^ 2 - c / a) ^ 0.5
           set x to {-r - s, r - s}
       on error -- Square root calculation too large.
           set x to {false, false}
       end try
   end if
   
   return x
end solveQuad

set {a, b, c} to {2, 4, -4}
solveQuad(a, b, c)

-- Result test. Both items here should be 0.0 or as near as dammit.
-- tell result to return {a * ((item 1) ^ 2) + b * (item 1) + c, a * ((item 2) ^ 2) + b * (item 2) + c}

Edit: Catches added for a = 0 and for square root calculation crashes.

Last edited by Nigel Garvey (2013-10-11 06:36:29 am)


NG

Offline

 

#5 2013-10-10 11:55:03 am

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Re: Quadratic Equation Solver

Hello.

I had returned an equation with the roots, that was rather confusing, I have now changed it to just deliver the roots, instead of delivering the roots with their value multiplicated with −1-

The roots I got out by running your example is −2.732050807569 and 0.732050807569. Those are returned directly now instead of being returned as (X + 2.732050807569) ( X - 0.732050807569). They both ( the real roots),  gives the result of zero when fed to this handler together with the coeffecients.

Applescript:

on f(a, b, c, x)
   set tmp to (a * (x ^ 2) + (b * x) + c)
   if (abs tmp) < 1.0E-12 then return 0
# Satimage osax for abs
   return tmp
end f

Edit

There may have been some mess with the sign of the roots, in all fairness, it should be ok now.

Last edited by McUsrII (2013-10-11 11:25:20 am)

Offline

 

#6 2015-06-27 03:42:08 am

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Re: Quadratic Equation Solver

Hello.

I have updated the script in post #1 with an |abs| handler of my own, so that the script is independent of any osax.

Edit

I found it easier to read the result, with the  "human readable" sign of the roots presented, so I changed that for the case when the roots are real and two different ones.

This is now a work in progress, so I won't bump it further before I'm done.

Last edited by McUsrII (2015-06-27 04:04:43 am)

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)