数値演算の関数を35個提供するAppleScript Libraries「calcLibAS」の高速版です。
–> Download calcLibAS (To ~/Library/Script Libraries/)
掘っ建て小屋とか犬小屋みたいな吹けば飛ぶような数値演算ライブラリだったものが、気づけば最初のバージョンから28倍速といったトンでもない状況になっています。ただ、前バージョンとくらべて少し安定性が損なわれているような気がしないでもありません。
計算に速度が求められる用途では、BridgePlusやSatimage OSAXなどを使うのがよいと思いますが、これらのライブラリやOSAXがサポートしていない数値関数が割とあるので(とくにatan2)それを埋めるためだけに本ライブラリは存在しています。
こうしてグラフで比較してみると、C++で書かれたSatimage OSAX、Objective-Cで書かれたCocoa Frameworkと1桁違うぐらいの処理速度でAppleScriptによる(JavaScript処理系呼んでますけど)数値演算ができているのは割とすごいと思います(自分ではなくCPUとかOSとかShane Stanleyの高速化とかが。割と他力本願ライブラリなので)。
本来であれば、AppleがNumbersの関数の充実のために導入した「Cephes Math Library」をNSNumberを介してAppleScriptから呼べるようにラッピングするのがよいのですが(Github上にあるObjectiveCephesは、単にCocoa Framework化しただけでC言語レベルでデータを扱っているのでAppleScriptからは使えない)、割と手間がかかるので「とりあえずJavaScriptの処理系の関数を使えるようにしてみよう」ということで(数時間で)でっち上げた、その場しのぎのためのライブラリです。
AppleScript名:testScript1 |
— Created 2018-06-06 by Takaaki Naganoya — 2018 Piyomaru Software use AppleScript version "2.5" use scripting additions use mLib : script "calcLibAS" set a01Res to calcAbs(-10) of mLib –> 10 set a02Res to calcAcos(-1) of mLib –> 3.14159265359 set a03Res to calcAcosh(10) of mLib –> 2.993222846126 set a04Res to calcAsin(-1) of mLib –> -1.570796326795 set a05Res to calcAsinh(10) of mLib –> 2.998222950298 set a06Res to calcAtan(10) of mLib –> 1.471127674304 set a07Res to calcAtan2(10, 20) of mLib –> 0.463647609001 set a08Res to calcAtanh(0.5) of mLib –> 0.549306144334 set a09Res to calcCbrt(3) of mLib –> 1.442249570307 set a10Res to calcCeil(0.95) of mLib –> 1 set a11Res to calcClz32(1) of mLib –> 31 set a12Res to calcCos(1) of mLib –> 0.540302305868 set a13Res to calcCosh(1) of mLib –> 1.543080634815 set a14Res to calcExp(1) of mLib –> 2.718281828459 set a15Res to calcExpm1(-1) of mLib –> -0.632120558829 set a16Res to calcFloor(45.95) of mLib –> 45 set a17Res to calcFround(1.337) of mLib –> 1.337000012398 set a18Res to calcHypot({3, 4, 5}) of mLib –> 7.071067811865 set a19Res to calcImul(2, 5) of mLib –> 10 set a20Res to calcLog(10) of mLib –> 2.302585092994 set a21Res to calcLog10(2) of mLib –> 0.301029995664 set a22Res to calcLog1p(1) of mLib –> 0.69314718056 set a23Res to calcLog2(3) of mLib –> 1.584962500721 set a24Res to calcMax({1, 2, 3, 4, 6, 2, 10}) of mLib –> 10 set a25Res to calcMin({1, 2, 3, 4, 6, 2, 10, 0}) of mLib –> 0 set a26Res to calcPow(7, 2) of mLib –> 49.0 set a27Res to calcRandom() of mLib –> 0.200867049467 set a28Res to calcRound(5.95) of mLib –> 6.0 set a29Res to calcSign(10) of mLib –> -1/0/1 –> -1.0/0.0/1.0 set a30Res to calcSin(pi / 2) of mLib –> 1–> 1.0 set a31Res to calcSinh(1) of mLib –> 1.175201193644 set a32Res to calcSqrt(2) of mLib –> 1.414213562373 set a33Res to calcTan(30) of mLib –> -6.405331196646 set a34Res to calcTanh(10) of mLib –> 0.999999995878 set a35Res to calcTrunc(13.37) of mLib –> 13 –> 13.0 |
AppleScript名:calcLibAS — Created 2018-06-06 by Takaaki Naganoya — 2017 Piyomaru Software –v1.0 First Version。run scriptでJXAを呼び出して計算。連続呼び出し時にクラッシュが頻発 –v1.1 JavaScriptCoreを使用。run script命令をフックして呼び出し。JXA呼び出しをやめて6倍の高速化 –v1.2 JavaScriptCoreを使用。run script命令のフックをやめて若干の高速化 –v1.3 Shane Stanleyによる高速化。JSContextをpropertyにキャッシュして高速化 |
— Created 2018-06-06 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.5" use scripting additions use framework "Foundation" use framework "JavaScriptCore" property theContext : missing value –数値の絶対値を返す on calcAbs(aNum as string) set aStr to "Math.abs(" & aNum & ")" return exeJS(aStr) end calcAbs –アークコサインをラジアン単位で返す on calcAcos(aNum as string) set aStr to "Math.acos(" & aNum & ")" return exeJS(aStr) end calcAcos –ハイパーボリックアークコサインを返す on calcAcosh(aNum as string) set aStr to "Math.acosh(" & aNum & ")" return exeJS(aStr) end calcAcosh –アークサインをラジアン単位で返す on calcAsin(aNum as string) set aStr to "Math.asin(" & aNum & ")" return exeJS(aStr) end calcAsin –ハイパーボリックアークサインを返す on calcAsinh(aNum as string) set aStr to "Math.asinh(" & aNum & ")" return exeJS(aStr) end calcAsinh –アークタンジェントをラジアン単位で返す on calcAtan(aNum as string) set aStr to "Math.atan(" & aNum & ")" return exeJS(aStr) end calcAtan –アークタンジェントを返す on calcAtan2(aNum as string, bNum as string) set aStr to "Math.atan2(" & aNum & ", " & bNum & ")" return exeJS(aStr) end calcAtan2 –ハイパーボリックアークタンジェントを返す on calcAtanh(aNum as string) set aStr to "Math.atanh(" & aNum & ")" return exeJS(aStr) end calcAtanh –引数として与えた数の立方根を返す on calcCbrt(aNum as string) set aStr to "Math.cbrt(" & aNum & ")" return exeJS(aStr) end calcCbrt –引数として与えた数以上の最小の整数を返す on calcCeil(aNum as string) set aStr to "Math.ceil(" & aNum & ")" return exeJS(aStr) end calcCeil –引数として与えた数以上の最小の整数を返す on calcClz32(aNum as string) set aStr to "Math.clz32(" & aNum & ")" return exeJS(aStr) end calcClz32 –引数として与えた数のコサインを返す on calcCos(aNum as string) set aStr to "Math.cos(" & aNum & ")" return exeJS(aStr) end calcCos –引数として与えた数のハイパーボリックコサインを返す on calcCosh(aNum as string) set aStr to "Math.cosh(" & aNum & ")" return exeJS(aStr) end calcCosh –Ex を返す。ここでの x は引数、E は、自然対数の底であるネイピア数(オイラー数) on calcExp(aNum as string) set aStr to "Math.exp(" & aNum & ")" return exeJS(aStr) end calcExp –ex – 1 を返す。x は引数で、e は自然対数の底 on calcExpm1(aNum as string) set aStr to "Math.expm1(" & aNum & ")" return exeJS(aStr) end calcExpm1 –引数として与えた数以下の最大の整数を返す on calcFloor(aNum as string) set aStr to "Math.floor(" & aNum & ")" return exeJS(aStr) end calcFloor –引数として与えた数の最も近い単精度 floatを返す on calcFround(aNum as string) set aStr to "Math.fround(" & aNum & ")" return exeJS(aStr) end calcFround –引数の二乗和の平方根を返す on calcHypot(aList as list) set bStr to retArrowText(aList, ", ") of me set aStr to "Math.hypot(" & bStr & ")" return exeJS(aStr) end calcHypot — 2 つの引数をとり、C 言語の様な 32 ビット乗算の結果を返す on calcImul(aNum as string, bNum as string) set aStr to "Math.imul(" & aNum & ", " & bNum & ")" return exeJS(aStr) end calcImul — 引数として与えた数の自然対数 (底は e) を返す on calcLog(aNum as string) set aStr to "Math.log(" & aNum & ")" return exeJS(aStr) end calcLog — 引数として与えた数に対して、10を底とする対数を返す on calcLog10(aNum as string) set aStr to "Math.log10(" & aNum & ")" return exeJS(aStr) end calcLog10 — 引数として与えた数と 1 の合計の自然対数(底 e)を返す on calcLog1p(aNum as string) set aStr to "Math.log1p(" & aNum & ")" return exeJS(aStr) end calcLog1p — 引数として与えた数の2を底とする対数を返す on calcLog2(aNum as string) set aStr to "Math.log2(" & aNum & ")" return exeJS(aStr) end calcLog2 –引数として与えた複数の数の中で最大の数を返す on calcMax(aList as list) set bStr to retArrowText(aList, ", ") of me set aStr to "Math.max(" & bStr & ")" return exeJS(aStr) end calcMax –引数として与えた複数の数の中で最小の数を返す on calcMin(aList as list) set bStr to retArrowText(aList, ", ") of me set aStr to "Math.min(" & bStr & ")" return exeJS(aStr) end calcMin –引数として与えた複数の数の中で最小の数を返す on calcPow(aNum as string, bNum as string) set aStr to "Math.pow(" & aNum & ", " & bNum & ")" return exeJS(aStr) end calcPow –(0以上、1未満)の範囲で浮動小数点の擬似乱数を返す on calcRandom() set aStr to "Math.random()" return (run script aStr in "JavaScript") end calcRandom –引数として与えた数を四捨五入して、もっとも近似の整数を返す on calcRound(aNum as string) set aStr to "Math.round(" & aNum & ")" return exeJS(aStr) end calcRound –引数として与えた数が正、負、0 のどれであるか示す符号を返す on calcSign(aNum as string) set aStr to "Math.sign(" & aNum & ")" return exeJS(aStr) end calcSign –引数として与えた数のサイン(正弦)を返す on calcSin(aNum as string) set aStr to "Math.sin(" & aNum & ")" return exeJS(aStr) end calcSin –引数として与えた数のハイパーボリックサインを返す on calcSinh(aNum as string) set aStr to "Math.sinh(" & aNum & ")" return exeJS(aStr) end calcSinh –引数として与えた数の平方根を返す on calcSqrt(aNum as string) set aStr to "Math.sqrt(" & aNum & ")" return exeJS(aStr) end calcSqrt –引数として与えた数のタンジェントを返す on calcTan(aNum as string) set aStr to "Math.tan(" & aNum & ")" return exeJS(aStr) end calcTan –引数として与えた数のハイパーボリックタンジェントを返す on calcTanh(aNum as string) set aStr to "Math.tanh(" & aNum & ")" return exeJS(aStr) end calcTanh –引数として与えた数の小数部の桁を取り除いて整数部を返す on calcTrunc(aNum as string) set aStr to "Math.trunc(" & aNum & ")" return exeJS(aStr) end calcTrunc –Sub Routines –リストを指定デリミタをはさんでテキスト化 on retArrowText(aList, aDelim) –自分のASでよく使うハンドラ名称なので、同じものを用意 set anArray to current application’s NSArray’s arrayWithArray:aList set aRes to anArray’s componentsJoinedByString:aDelim return aRes as text end retArrowText –JavaScriptCore版実行部 on exeJS(aStr) return (myContext()’s evaluateScript:aStr)’s toDouble() end exeJS on myContext() if theContext = missing value then set theContext to current application’s JSContext’s new() return theContext end myContext |