Saturday, January 20, 2018

You are not logged in.

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

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

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 03:02:58 am)

Offline

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

Registered: 2005-10-04
Posts: 4660

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 05:13:05 pm

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

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.

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 05:18:37 pm)

Offline

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

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

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:

-- 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}
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

set {a, b, c} to {2, 4, -4}

-- 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 05:36:29 am)

NG

Offline

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

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

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 10:25:20 am)

Offline

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

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

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 03:04:43 am)

Offline