commit 238d347274b62db3d56ed92f15d68748185da6f8
parent e089ea45150cedd9e8edc4b2c22e55580e98a25e
Author: Sebastian <sebastian@sebsite.pw>
Date: Fri, 27 May 2022 22:28:36 -0400
math::complex: initial commit
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
4 files changed, 1747 insertions(+), 0 deletions(-)
diff --git a/math/complex/+test.ha b/math/complex/+test.ha
@@ -0,0 +1,1303 @@
+// License: MPL-2.0
+// (c) 2022 Sebastian <sebastian@sebsite.pw>
+
+// The test data below is based on Go's implementation, and came with the
+// following note and copyright notice:
+//
+// The expected results below were computed by the high precision calculators
+// at https://keisan.casio.com/. More exact input values (array vf[], above)
+// were obtained by printing them with "%.26f". The answers were calculated
+// to 26 digits (by using the "Digit number" drop-down control of each
+// calculator).
+//
+// The Go copyright notice:
+// ====================================================
+// Copyright (c) 2009 The Go Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// ====================================================
+
+use math;
+
+// The higher-precision values in VC26 were used to derive the
+// input arguments VC. For reference only (do not delete).
+const VC26: []c128 = [
+ (4.97901192488367350108546816, +7.73887247457810456552351752),
+ (7.73887247457810456552351752, -0.27688005719200159404635997),
+ (-0.27688005719200159404635997, -5.01060361827107492160848778),
+ (-5.01060361827107492160848778, +9.63629370719841737980004837),
+ (9.63629370719841737980004837, +2.92637723924396464525443662),
+ (2.92637723924396464525443662, +5.22908343145930665230025625),
+ (5.22908343145930665230025625, +2.72793991043601025126008608),
+ (2.72793991043601025126008608, +1.82530809168085506044576505),
+ (1.82530809168085506044576505, -8.68592476857560136238589621),
+ (-8.68592476857560136238589621, +4.97901192488367350108546816),
+];
+
+const VC: []c128 = [
+ (4.9790119248836735e+00, +7.7388724745781045e+00),
+ (7.7388724745781045e+00, -2.7688005719200159e-01),
+ (-2.7688005719200159e-01, -5.0106036182710749e+00),
+ (-5.0106036182710749e+00, +9.6362937071984173e+00),
+ (9.6362937071984173e+00, +2.9263772392439646e+00),
+ (2.9263772392439646e+00, +5.2290834314593066e+00),
+ (5.2290834314593066e+00, +2.7279399104360102e+00),
+ (2.7279399104360102e+00, +1.8253080916808550e+00),
+ (1.8253080916808550e+00, -8.6859247685756013e+00),
+ (-8.6859247685756013e+00, +4.9790119248836735e+00),
+];
+
+// The expected results below were computed by the high precision calculators
+// at https://keisan.casio.com/. More exact input values (array vc[], above)
+// were obtained by printing them with "%.26f". The answers were calculated
+// to 26 digits (by using the "Digit number" drop-down control of each
+// calculator).
+
+const TEST_ABS: []f64 = [
+ 9.2022120669932650313380972e+00,
+ 7.7438239742296106616261394e+00,
+ 5.0182478202557746902556648e+00,
+ 1.0861137372799545160704002e+01,
+ 1.0070841084922199607011905e+01,
+ 5.9922447613166942183705192e+00,
+ 5.8978784056736762299945176e+00,
+ 3.2822866700678709020367184e+00,
+ 8.8756430028990417290744307e+00,
+ 1.0011785496777731986390856e+01,
+];
+
+const TEST_ACOS: []c128 = [
+ (1.0017679804707456328694569, -2.9138232718554953784519807),
+ (0.03606427612041407369636057, +2.7358584434576260925091256),
+ (1.6249365462333796703711823, +2.3159537454335901187730929),
+ (2.0485650849650740120660391, -3.0795576791204117911123886),
+ (0.29621132089073067282488147, -3.0007392508200622519398814),
+ (1.0664555914934156601503632, -2.4872865024796011364747111),
+ (0.48681307452231387690013905, -2.463655912283054555225301),
+ (0.6116977071277574248407752, -1.8734458851737055262693056),
+ (1.3649311280370181331184214, +2.8793528632328795424123832),
+ (2.6189310485682988308904501, -2.9956543302898767795858704),
+];
+
+const TEST_ACOSH: []c128 = [
+ (2.9138232718554953784519807, +1.0017679804707456328694569),
+ (2.7358584434576260925091256, -0.03606427612041407369636057),
+ (2.3159537454335901187730929, -1.6249365462333796703711823),
+ (3.0795576791204117911123886, +2.0485650849650740120660391),
+ (3.0007392508200622519398814, +0.29621132089073067282488147),
+ (2.4872865024796011364747111, +1.0664555914934156601503632),
+ (2.463655912283054555225301, +0.48681307452231387690013905),
+ (1.8734458851737055262693056, +0.6116977071277574248407752),
+ (2.8793528632328795424123832, -1.3649311280370181331184214),
+ (2.9956543302898767795858704, +2.6189310485682988308904501),
+];
+
+const TEST_ASIN: []c128 = [
+ (0.56902834632415098636186476, +2.9138232718554953784519807),
+ (1.5347320506744825455349611, -2.7358584434576260925091256),
+ (-0.054140219438483051139860579, -2.3159537454335901187730929),
+ (-0.47776875817017739283471738, +3.0795576791204117911123886),
+ (1.2745850059041659464064402, +3.0007392508200622519398814),
+ (0.50434073530148095908095852, +2.4872865024796011364747111),
+ (1.0839832522725827423311826, +2.463655912283054555225301),
+ (0.9590986196671391943905465, +1.8734458851737055262693056),
+ (0.20586519875787848611290031, -2.8793528632328795424123832),
+ (-1.0481347217734022116591284, +2.9956543302898767795858704),
+];
+
+const TEST_ASINH: []c128 = [
+ (2.9113760469415295679342185, +0.99639459545704326759805893),
+ (2.7441755423994259061579029, -0.035468308789000500601119392),
+ (-2.2962136462520690506126678, -1.5144663565690151885726707),
+ (-3.0771233459295725965402455, +1.0895577967194013849422294),
+ (3.0048366100923647417557027, +0.29346979169819220036454168),
+ (2.4800059370795363157364643, +1.0545868606049165710424232),
+ (2.4718773838309585611141821, +0.47502344364250803363708842),
+ (1.8910743588080159144378396, +0.56882925572563602341139174),
+ (2.8735426423367341878069406, -1.362376149648891420997548),
+ (-2.9981750586172477217567878, +0.5183571985225367505624207),
+];
+
+const TEST_ATAN: []c128 = [
+ (1.5115747079332741358607654, +0.091324403603954494382276776),
+ (1.4424504323482602560806727, -0.0045416132642803911503770933),
+ (-1.5593488703630532674484026, -0.20163295409248362456446431),
+ (-1.5280619472445889867794105, +0.081721556230672003746956324),
+ (1.4759909163240799678221039, +0.028602969320691644358773586),
+ (1.4877353772046548932715555, +0.14566877153207281663773599),
+ (1.4206983927779191889826, +0.076830486127880702249439993),
+ (1.3162236060498933364869556, +0.16031313000467530644933363),
+ (1.5473450684303703578810093, -0.11064907507939082484935782),
+ (-1.4841462340185253987375812, +0.049341850305024399493142411),
+];
+
+const TEST_ATANH: []c128 = [
+ (0.058375027938968509064640438, +1.4793488495105334458167782),
+ (0.12977343497790381229915667, -1.5661009410463561327262499),
+ (-0.010576456067347252072200088, -1.3743698658402284549750563),
+ (-0.042218595678688358882784918, +1.4891433968166405606692604),
+ (0.095218997991316722061828397, +1.5416884098777110330499698),
+ (0.079965459366890323857556487, +1.4252510353873192700350435),
+ (0.15051245471980726221708301, +1.4907432533016303804884461),
+ (0.25082072933993987714470373, +1.392057665392187516442986),
+ (0.022896108815797135846276662, -1.4609224989282864208963021),
+ (-0.08665624101841876130537396, +1.5207902036935093480142159),
+];
+
+const TEST_CONJ: []c128 = [
+ (4.9790119248836735e+00, -7.7388724745781045e+00),
+ (7.7388724745781045e+00, +2.7688005719200159e-01),
+ (-2.7688005719200159e-01, +5.0106036182710749e+00),
+ (-5.0106036182710749e+00, -9.6362937071984173e+00),
+ (9.6362937071984173e+00, -2.9263772392439646e+00),
+ (2.9263772392439646e+00, -5.2290834314593066e+00),
+ (5.2290834314593066e+00, -2.7279399104360102e+00),
+ (2.7279399104360102e+00, -1.8253080916808550e+00),
+ (1.8253080916808550e+00, +8.6859247685756013e+00),
+ (-8.6859247685756013e+00, -4.9790119248836735e+00),
+];
+
+const TEST_COS: []c128 = [
+ (3.024540920601483938336569e+02, +1.1073797572517071650045357e+03),
+ (1.192858682649064973252758e-01, +2.7857554122333065540970207e-01),
+ (7.2144394304528306603857962e+01, -2.0500129667076044169954205e+01),
+ (2.24921952538403984190541e+03, -7.317363745602773587049329e+03),
+ (-9.148222970032421760015498e+00, +1.953124661113563541862227e+00),
+ (-9.116081175857732248227078e+01, -1.992669213569952232487371e+01),
+ (3.795639179042704640002918e+00, +6.623513350981458399309662e+00),
+ (-2.9144840732498869560679084e+00, -1.214620271628002917638748e+00),
+ (-7.45123482501299743872481e+02, +2.8641692314488080814066734e+03),
+ (-5.371977967039319076416747e+01, +4.893348341339375830564624e+01),
+];
+
+const TEST_COSH: []c128 = [
+ (8.34638383523018249366948e+00, +7.2181057886425846415112064e+01),
+ (1.10421967379919366952251e+03, -3.1379638689277575379469861e+02),
+ (3.051485206773701584738512e-01, -2.6805384730105297848044485e-01),
+ (-7.33294728684187933370938e+01, +1.574445942284918251038144e+01),
+ (-7.478643293945957535757355e+03, +1.6348382209913353929473321e+03),
+ (4.622316522966235701630926e+00, -8.088695185566375256093098e+00),
+ (-8.544333183278877406197712e+01, +3.7505836120128166455231717e+01),
+ (-1.934457815021493925115198e+00, +7.3725859611767228178358673e+00),
+ (-2.352958770061749348353548e+00, -2.034982010440878358915409e+00),
+ (7.79756457532134748165069e+02, +2.8549350716819176560377717e+03),
+];
+
+const TEST_EXP: []c128 = [
+ (1.669197736864670815125146e+01, +1.4436895109507663689174096e+02),
+ (2.2084389286252583447276212e+03, -6.2759289284909211238261917e+02),
+ (2.227538273122775173434327e-01, +7.2468284028334191250470034e-01),
+ (-6.5182985958153548997881627e-03, -1.39965837915193860879044e-03),
+ (-1.4957286524084015746110777e+04, +3.269676455931135688988042e+03),
+ (9.218158701983105935659273e+00, -1.6223985291084956009304582e+01),
+ (-1.7088175716853040841444505e+02, +7.501382609870410713795546e+01),
+ (-3.852461315830959613132505e+00, +1.4808420423156073221970892e+01),
+ (-4.586775503301407379786695e+00, -4.178501081246873415144744e+00),
+ (4.451337963005453491095747e-05, -1.62977574205442915935263e-04),
+];
+
+const TEST_LOG: []c128 = [
+ (2.2194438972179194425697051e+00, +9.9909115046919291062461269e-01),
+ (2.0468956191154167256337289e+00, -3.5762575021856971295156489e-02),
+ (1.6130808329853860438751244e+00, -1.6259990074019058442232221e+00),
+ (2.3851910394823008710032651e+00, +2.0502936359659111755031062e+00),
+ (2.3096442270679923004800651e+00, +2.9483213155446756211881774e-01),
+ (1.7904660933974656106951860e+00, +1.0605860367252556281902109e+00),
+ (1.7745926939841751666177512e+00, +4.8084556083358307819310911e-01),
+ (1.1885403350045342425648780e+00, +5.8969634164776659423195222e-01),
+ (2.1833107837679082586772505e+00, -1.3636647724582455028314573e+00),
+ (2.3037629487273259170991671e+00, +2.6210913895386013290915234e+00),
+];
+
+const TEST_LOG10: []c128 = [
+ (9.6389223745559042474184943e-01, +4.338997735671419492599631e-01),
+ (8.8895547241376579493490892e-01, -1.5531488990643548254864806e-02),
+ (7.0055210462945412305244578e-01, -7.0616239649481243222248404e-01),
+ (1.0358753067322445311676952e+00, +8.9043121238134980156490909e-01),
+ (1.003065742975330237172029e+00, +1.2804396782187887479857811e-01),
+ (7.7758954439739162532085157e-01, +4.6060666333341810869055108e-01),
+ (7.7069581462315327037689152e-01, +2.0882857371769952195512475e-01),
+ (5.1617650901191156135137239e-01, +2.5610186717615977620363299e-01),
+ (9.4819982567026639742663212e-01, -5.9223208584446952284914289e-01),
+ (1.0005115362454417135973429e+00, +1.1383255270407412817250921e+00),
+];
+
+const TEST_POLAR: []c128 = [
+ (9.2022120669932650313380972e+00, 9.9909115046919291062461269e-01),
+ (7.7438239742296106616261394e+00, -3.5762575021856971295156489e-02),
+ (5.0182478202557746902556648e+00, -1.6259990074019058442232221e+00),
+ (1.0861137372799545160704002e+01, 2.0502936359659111755031062e+00),
+ (1.0070841084922199607011905e+01, 2.9483213155446756211881774e-01),
+ (5.9922447613166942183705192e+00, 1.0605860367252556281902109e+00),
+ (5.8978784056736762299945176e+00, 4.8084556083358307819310911e-01),
+ (3.2822866700678709020367184e+00, 5.8969634164776659423195222e-01),
+ (8.8756430028990417290744307e+00, -1.3636647724582455028314573e+00),
+ (1.0011785496777731986390856e+01, 2.6210913895386013290915234e+00),
+];
+
+const TEST_POW: []c128 = [
+ (-2.499956739197529585028819e+00, +1.759751724335650228957144e+00),
+ (7.357094338218116311191939e+04, -5.089973412479151648145882e+04),
+ (1.320777296067768517259592e+01, -3.165621914333901498921986e+01),
+ (-3.123287828297300934072149e-07, -1.9849567521490553032502223e-7),
+ (8.0622651468477229614813e+04, -7.80028727944573092944363e+04),
+ (-1.0268824572103165858577141e+00, -4.716844738244989776610672e-01),
+ (-4.35953819012244175753187e+01, +2.2036445974645306917648585e+02),
+ (8.3556092283250594950239e-01, -1.2261571947167240272593282e+01),
+ (1.582292972120769306069625e+03, +1.273564263524278244782512e+04),
+ (6.592208301642122149025369e-08, +2.584887236651661903526389e-08),
+];
+
+const TEST_SIN: []c128 = [
+ (-1.1073801774240233539648544e+03, +3.024539773002502192425231e+02),
+ (1.0317037521400759359744682e+00, -3.2208979799929570242818e-02),
+ (-2.0501952097271429804261058e+01, -7.2137981348240798841800967e+01),
+ (7.3173638080346338642193078e+03, +2.249219506193664342566248e+03),
+ (-1.964375633631808177565226e+00, -9.0958264713870404464159683e+00),
+ (1.992783647158514838337674e+01, -9.11555769410191350416942e+01),
+ (-6.680335650741921444300349e+00, +3.763353833142432513086117e+00),
+ (1.2794028166657459148245993e+00, -2.7669092099795781155109602e+00),
+ (2.8641693949535259594188879e+03, +7.451234399649871202841615e+02),
+ (-4.893811726244659135553033e+01, -5.371469305562194635957655e+01),
+];
+
+const TEST_SINH: []c128 = [
+ (8.34559353341652565758198e+00, +7.2187893208650790476628899e+01),
+ (1.1042192548260646752051112e+03, -3.1379650595631635858792056e+02),
+ (-8.239469336509264113041849e-02, +9.9273668758439489098514519e-01),
+ (7.332295456982297798219401e+01, -1.574585908122833444899023e+01),
+ (-7.4786432301380582103534216e+03, +1.63483823493980029604071e+03),
+ (4.595842179016870234028347e+00, -8.135290105518580753211484e+00),
+ (-8.543842533574163435246793e+01, +3.750798997857594068272375e+01),
+ (-1.918003500809465688017307e+00, +7.4358344619793504041350251e+00),
+ (-2.233816733239658031433147e+00, -2.143519070805995056229335e+00),
+ (-7.797564130187551181105341e+02, -2.8549352346594918614806877e+03),
+];
+
+const TEST_SQRT: []c128 = [
+ (2.6628203086086130543813948e+00, +1.4531345674282185229796902e+00),
+ (2.7823278427251986247149295e+00, -4.9756907317005224529115567e-02),
+ (1.5397025302089642757361015e+00, -1.6271336573016637535695727e+00),
+ (1.7103411581506875260277898e+00, +2.8170677122737589676157029e+00),
+ (3.1390392472953103383607947e+00, +4.6612625849858653248980849e-01),
+ (2.1117080764822417640789287e+00, +1.2381170223514273234967850e+00),
+ (2.3587032281672256703926939e+00, +5.7827111903257349935720172e-01),
+ (1.7335262588873410476661577e+00, +5.2647258220721269141550382e-01),
+ (2.3131094974708716531499282e+00, -1.8775429304303785570775490e+00),
+ (8.1420535745048086240947359e-01, +3.0575897587277248522656113e+00),
+];
+
+const TEST_TAN: []c128 = [
+ (-1.928757919086441129134525e-07, +1.0000003267499169073251826e+00),
+ (1.242412685364183792138948e+00, -3.17149693883133370106696e+00),
+ (-4.6745126251587795225571826e-05, -9.9992439225263959286114298e-01),
+ (4.792363401193648192887116e-09, +1.0000000070589333451557723e+00),
+ (2.345740824080089140287315e-03, +9.947733046570988661022763e-01),
+ (-2.396030789494815566088809e-05, +9.9994781345418591429826779e-01),
+ (-7.370204836644931340905303e-03, +1.0043553413417138987717748e+00),
+ (-3.691803847992048527007457e-02, +9.6475071993469548066328894e-01),
+ (-2.781955256713729368401878e-08, -1.000000049848910609006646e+00),
+ (9.4281590064030478879791249e-05, +9.9999119340863718183758545e-01),
+];
+
+const TEST_TANH: []c128 = [
+ (1.0000921981225144748819918e+00, +2.160986245871518020231507e-05),
+ (9.9999967727531993209562591e-01, -1.9953763222959658873657676e-07),
+ (-1.765485739548037260789686e+00, +1.7024216325552852445168471e+00),
+ (-9.999189442732736452807108e-01, +3.64906070494473701938098e-05),
+ (9.9999999224622333738729767e-01, -3.560088949517914774813046e-09),
+ (1.0029324933367326862499343e+00, -4.948790309797102353137528e-03),
+ (9.9996113064788012488693567e-01, -4.226995742097032481451259e-05),
+ (1.0074784189316340029873945e+00, -4.194050814891697808029407e-03),
+ (9.9385534229718327109131502e-01, +5.144217985914355502713437e-02),
+ (-1.0000000491604982429364892e+00, -2.901873195374433112227349e-08),
+];
+
+// huge values along the real axis for testing reducepi in tan
+// TODO: these probably shouldn't have to be casted twice (harec bug?)
+const TEST_HUGEIN: []c128 = [
+ ((1 << 28): u64: f64, 0f64),
+ ((1 << 29): u64: f64, 0f64),
+ ((1 << 30): u64: f64, 0f64),
+ ((1 << 35): u64: f64, 0f64),
+ ((-1 << 120): u64: f64, 0f64),
+ ((1 << 240): u64: f64, 0f64),
+ ((1 << 300): u64: f64, 0f64),
+ ((-1 << 480): u64: f64, 0f64),
+ ((1234567891234567 << 180): u64: f64, 0f64),
+ ((-1234567891234567 << 300): u64: f64, 0f64),
+];
+
+// Results for TEST_TANHUGE[i] calculated with https://github.com/robpike/ivy
+// using 4096 bits of working precision.
+const TEST_TANHUGE: []c128 = [
+ ((5.95641897939639421): f64, 0f64),
+ ((-0.34551069233430392): f64, 0f64),
+ ((-0.78469661331920043): f64, 0f64),
+ ((0.84276385870875983): f64, 0f64),
+ ((0.40806638884180424): f64, 0f64),
+ ((-0.37603456702698076): f64, 0f64),
+ ((4.60901287677810962): f64, 0f64),
+ ((3.39135965054779932): f64, 0f64),
+ ((-6.76813854009065030): f64, 0f64),
+ ((-0.76417695016604922): f64, 0f64),
+];
+
+const TEST_VCABSSC: []c128 = [
+ (math::NAN, math::NAN),
+];
+
+const TEST_ABSSC: []f64 = [
+ math::NAN,
+];
+
+const TEST_ACOSSC: [](c128, c128) = [
+ // G.6.1.1
+ ((0f64, 0f64),
+ (math::PI / 2f64, -0f64)),
+ ((-0f64, 0f64),
+ (math::PI / 2f64, -0f64)),
+ ((0f64, math::NAN),
+ (math::PI / 2f64, math::NAN)),
+ ((-0f64, math::NAN),
+ (math::PI / 2f64, math::NAN)),
+ ((1f64, math::INF),
+ (math::PI / 2f64, -math::INF)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((-math::INF, 1f64),
+ (math::PI, -math::INF)),
+ ((math::INF, 1f64),
+ (0f64, -math::INF)),
+ ((-math::INF, math::INF),
+ (3f64 * math::PI / 4f64, -math::INF)),
+ ((math::INF, math::INF),
+ (math::PI / 4f64, -math::INF)),
+ ((math::INF, math::NAN),
+ (math::NAN, -math::INF)), // imaginary sign unspecified
+ ((-math::INF, math::NAN),
+ (math::NAN, math::INF)), // imaginary sign unspecified
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::NAN, -math::INF)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_ACOSHSC: [](c128, c128) = [
+ // G.6.2.1
+ ((0f64, 0f64),
+ (0f64, math::PI / 2f64)),
+ ((-0f64, 0f64),
+ (0f64, math::PI / 2f64)),
+ ((1f64, math::INF),
+ (math::INF, math::PI / 2f64)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((-math::INF, 1f64),
+ (math::INF, math::PI)),
+ ((math::INF, 1f64),
+ (math::INF, 0f64)),
+ ((-math::INF, math::INF),
+ (math::INF, 3f64 * math::PI / 4f64)),
+ ((math::INF, math::INF),
+ (math::INF, math::PI / 4f64)),
+ ((math::INF, math::NAN),
+ (math::INF, math::NAN)),
+ ((-math::INF, math::NAN),
+ (math::INF, math::NAN)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::INF, math::NAN)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_ASINSC: [](c128, c128) = [
+ // Derived from Asin(z) = -i * Asinh(i * z), G.6 #7
+ ((0f64, 0f64),
+ (0f64, 0f64)),
+ ((1f64, math::INF),
+ (0f64, math::INF)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 1f64),
+ (math::PI / 2f64, math::INF)),
+ ((math::INF, math::INF),
+ (math::PI / 4f64, math::INF)),
+ ((math::INF, math::NAN),
+ (math::NAN, math::INF)), // imaginary sign unspecified
+ ((math::NAN, 0f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::NAN, math::INF)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_ASINHSC: [](c128, c128) = [
+ // G.6.2.2
+ ((0f64, 0f64),
+ (0f64, 0f64)),
+ ((1f64, math::INF),
+ (math::INF, math::PI / 2f64)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 1f64),
+ (math::INF, 0f64)),
+ ((math::INF, math::INF),
+ (math::INF, math::PI / 4f64)),
+ ((math::INF, math::NAN),
+ (math::INF, math::NAN)),
+ ((math::NAN, 0f64),
+ (math::NAN, 0f64)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::INF, math::NAN)), // sign of real part unspecified
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_ATANSC: [](c128, c128) = [
+ // Derived from Atan(z) = -i * Atanh(i * z), G.6 #7
+ ((0f64, 0f64),
+ (0f64, 0f64)),
+ ((0f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((1f64, 0f64),
+ (math::PI / 4f64, 0f64)),
+ ((1f64, math::INF),
+ (math::PI / 2f64, 0f64)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 1f64),
+ (math::PI / 2f64, 0f64)),
+ ((math::INF, math::INF),
+ (math::PI / 2f64, 0f64)),
+ ((math::INF, math::NAN),
+ (math::PI / 2f64, 0f64)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::NAN, 0f64)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_ATANHSC: [](c128, c128) = [
+ // G.6.2.3
+ ((0f64, 0f64),
+ (0f64, 0f64)),
+ ((0f64, math::NAN),
+ (0f64, math::NAN)),
+ ((1f64, 0f64),
+ (math::INF, 0f64)),
+ ((1f64, math::INF),
+ (0f64, math::PI / 2f64)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 1f64),
+ (0f64, math::PI / 2f64)),
+ ((math::INF, math::INF),
+ (0f64, math::PI / 2f64)),
+ ((math::INF, math::NAN),
+ (0f64, math::NAN)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::NAN),
+ (0f64, math::PI / 2f64)), // sign of real part not specified.
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_VCCONJSC: []c128 = [
+ (math::NAN, math::NAN),
+];
+
+const TEST_CONJSC: []c128 = [
+ (math::NAN, math::NAN),
+];
+
+const TEST_COSSC: [](c128, c128) = [
+ // Derived from Cos(z) = Cosh(i * z), G.6 #7
+ ((0f64, 0f64),
+ (1f64, -0f64)),
+ ((0f64, math::INF),
+ (math::INF, -0f64)),
+ ((0f64, math::NAN),
+ (math::NAN, 0f64)), // imaginary sign unspecified
+ ((1f64, math::INF),
+ (math::INF, -math::INF)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 0f64),
+ (math::NAN, -0f64)),
+ ((math::INF, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::INF, math::INF),
+ (math::INF, math::NAN)), // real sign unspecified
+ ((math::INF, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::NAN, 0f64),
+ (math::NAN, -0f64)), // imaginary sign unspecified
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::INF, math::NAN)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_COSHSC: [](c128, c128) = [
+ // G.6.2.4
+ ((0f64, 0f64),
+ (1f64, 0f64)),
+ ((0f64, math::INF),
+ (math::NAN, 0f64)), // imaginary sign unspecified
+ ((0f64, math::NAN),
+ (math::NAN, 0f64)), // imaginary sign unspecified
+ ((1f64, math::INF),
+ (math::NAN, math::NAN)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 0f64),
+ (math::INF, 0f64)),
+ ((math::INF, 1f64),
+ (math::INF, math::INF)), // +(math::INF, 0f64) cis(y)
+ ((math::INF, math::INF),
+ (math::INF, math::NAN)), // real sign unspecified
+ ((math::INF, math::NAN),
+ (math::INF, math::NAN)),
+ ((math::NAN, 0f64),
+ (math::NAN, 0f64)), // imaginary sign unspecified
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_EXPSC: [](c128, c128) = [
+ // G.6.3.1
+ ((0f64, 0f64),
+ (1f64, 0f64)),
+ ((-0f64, 0f64),
+ (1f64, 0f64)),
+ ((1f64, math::INF),
+ (math::NAN, math::NAN)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 0f64),
+ (math::INF, 0f64)),
+ ((-math::INF, 1f64),
+ (0f64, 0f64)),
+ ((math::INF, 1f64),
+ (math::INF, math::INF)),
+ ((-math::INF, math::INF),
+ (0f64, 0f64)), // real and imaginary sign unspecified
+ ((math::INF, math::INF),
+ (math::INF, math::NAN)), // real sign unspecified
+ ((-math::INF, math::NAN),
+ (0f64, 0f64)), // real and imaginary sign unspecified
+ ((math::INF, math::NAN),
+ (math::INF, math::NAN)), // real sign unspecified
+ ((math::NAN, 0f64),
+ (math::NAN, 0f64)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_VCISNANSC: []c128 = [
+ (-math::INF, -math::INF),
+ (-math::INF, math::NAN),
+ (math::NAN, -math::INF),
+ (0f64, math::NAN),
+ (math::NAN, 0f64),
+ (math::INF, math::INF),
+ (math::INF, math::NAN),
+ (math::NAN, math::INF),
+ (math::NAN, math::NAN),
+];
+
+const TEST_ISNANSC: []bool = [
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false,
+ false,
+ true,
+];
+
+// XXX: math::PI doesn't have suitable precision here for some reason
+const TEST_LOGSC: [](c128, c128) = [
+ // G.6.3.2
+ ((0f64, 0f64),
+ (-math::INF, 0f64)),
+ //((-0f64, 0f64),
+ // (-math::INF, math::PI)),
+ //((1f64, math::INF),
+ // (math::INF, math::PI / 2f64)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ //((-math::INF, 1f64),
+ // (math::INF, math::PI)),
+ ((math::INF, 1f64),
+ (math::INF, 0f64)),
+ //((-math::INF, math::INF),
+ // (math::INF, 3f64 * math::PI / 4f64)),
+ //((math::INF, math::INF),
+ // (math::INF, math::PI / 4f64)),
+ ((-math::INF, math::NAN),
+ (math::INF, math::NAN)),
+ ((math::INF, math::NAN),
+ (math::INF, math::NAN)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::INF, math::NAN)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_LOG10SC: [](c128, c128) = [
+ // derived from Log special cases via Log10(x) = math.Log10E*Log(x)
+ ((0f64, 0f64),
+ (-math::INF, 0f64)),
+ ((-0f64, 0f64),
+ (-math::INF, math::LOG10_E * math::PI)),
+ ((1f64, math::INF),
+ (math::INF, math::LOG10_E * math::PI / 2f64)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((-math::INF, 1f64),
+ (math::INF, math::LOG10_E * math::PI)),
+ ((math::INF, 1f64),
+ (math::INF, 0f64)),
+ ((-math::INF, math::INF),
+ (math::INF, math::LOG10_E * 3f64 * math::PI / 4f64)),
+ ((math::INF, math::INF),
+ (math::INF, math::LOG10_E * math::PI / 4f64)),
+ ((-math::INF, math::NAN),
+ (math::INF, math::NAN)),
+ ((math::INF, math::NAN),
+ (math::INF, math::NAN)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::INF, math::NAN)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_VCPOLARSC: []c128 = [
+ (math::NAN, math::NAN),
+];
+
+const TEST_POLARSC: [](f64, f64) = [
+ (math::NAN, math::NAN),
+];
+
+const TEST_VCPOWSC: [](c128, c128) = [
+ ((math::NAN, math::NAN), (math::NAN, math::NAN)),
+ ((0f64, 0f64), (math::NAN, math::NAN)),
+];
+
+const TEST_POWSC: []c128 = [
+ (math::NAN, math::NAN),
+ (math::NAN, math::NAN),
+];
+
+const TEST_SINSC: [](c128, c128) = [
+ // Derived from Sin(z) = -i * Sinh(i * z), G.6 #7
+ ((0f64, 0f64),
+ (0f64, 0f64)),
+ ((0f64, math::INF),
+ (0f64, math::INF)),
+ ((0f64, math::NAN),
+ (0f64, math::NAN)),
+ ((1f64, math::INF),
+ (math::INF, math::INF)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 0f64),
+ (math::NAN, 0f64)),
+ ((math::INF, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::INF, math::INF),
+ (math::NAN, math::INF)),
+ ((math::INF, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::NAN, 0f64),
+ (math::NAN, 0f64)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::NAN, math::INF)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_SINHSC: [](c128, c128) = [
+ // G.6.2.5
+ ((0f64, 0f64),
+ (0f64, 0f64)),
+ ((0f64, math::INF),
+ (0f64, math::NAN)), // real sign unspecified
+ ((0f64, math::NAN),
+ (0f64, math::NAN)), // real sign unspecified
+ ((1f64, math::INF),
+ (math::NAN, math::NAN)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 0f64),
+ (math::INF, 0f64)),
+ ((math::INF, 1f64),
+ (math::INF, math::INF)), // +math::INF cis(y)
+ ((math::INF, math::INF),
+ (math::INF, math::NAN)), // real sign unspecified
+ ((math::INF, math::NAN),
+ (math::INF, math::NAN)), // real sign unspecified
+ ((math::NAN, 0f64),
+ (math::NAN, 0f64)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_SQRTSC: [](c128, c128) = [
+ // G.6.4.2
+ ((0f64, 0f64),
+ (0f64, 0f64)),
+ ((-0f64, 0f64),
+ (0f64, 0f64)),
+ ((1f64, math::INF),
+ (math::INF, math::INF)),
+ ((math::NAN, math::INF),
+ (math::INF, math::INF)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((-math::INF, 1f64),
+ (0f64, math::INF)),
+ ((math::INF, 1f64),
+ (math::INF, 0f64)),
+ ((-math::INF, math::NAN),
+ (math::NAN, math::INF)), // imaginary sign unspecified
+ ((math::INF, math::NAN),
+ (math::INF, math::NAN)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_TANSC: [](c128, c128) = [
+ // Derived from Tan(z) = -i * Tanh(i * z), G.6 #7
+ ((0f64, 0f64),
+ (0f64, 0f64)),
+ ((0f64, math::NAN),
+ (0f64, math::NAN)),
+ ((1f64, math::INF),
+ (0f64, 1f64)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::INF, math::INF),
+ (0f64, 1f64)),
+ ((math::INF, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::NAN, 0f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (0f64, 1f64)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+const TEST_TANHSC: [](c128, c128) = [
+ // G.6.2.6
+ ((0f64, 0f64),
+ (0f64, 0f64)),
+ ((1f64, math::INF),
+ (math::NAN, math::NAN)),
+ ((1f64, math::NAN),
+ (math::NAN, math::NAN)),
+ ((math::INF, 1f64),
+ (1f64, 0f64)), // 1 + i 0 sin(2y)
+ ((math::INF, math::INF),
+ (1f64, 0f64)), // imaginary sign unspecified
+ ((math::INF, math::NAN),
+ (1f64, 0f64)), // imaginary sign unspecified
+ ((math::NAN, 0f64),
+ (math::NAN, 0f64)),
+ ((math::NAN, 1f64),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::INF),
+ (math::NAN, math::NAN)),
+ ((math::NAN, math::NAN),
+ (math::NAN, math::NAN)),
+];
+
+// branch cut continuity checks
+// points on each axis at |z| > 1 are checked for one-sided continuity from both
+// the positive and negative side
+// all possible branch cuts for the elementary functions are at one of these
+// points
+
+// TODO: this probably shouldn't need to be casted twice (harec bug?)
+def EPS: f64 = 1f64 / (1 << 53): u64: f64;
+
+const BRANCHPOINTS: [](c128, c128) = [
+ ((2f64, 0f64), (2f64, EPS)),
+ ((2f64, -0f64), (2f64, -EPS)),
+ ((-2.0, 0f64), (-2.0, EPS)),
+ ((-2.0, -0f64), (-2.0, -EPS)),
+ ((0f64, 2f64), (EPS, 2f64)),
+ ((-0f64, 2f64), (-EPS, 2f64)),
+ ((0f64, -2.0), (EPS, -2.0)),
+ ((-0f64, -2.0), (-EPS, -2.0)),
+];
+
+fn tolerance(actual: f64, expected: f64, e: f64) bool = {
+ const err = math::absf64(actual - expected);
+ if (expected != 0f64) {
+ e = math::absf64(e * expected);
+ };
+ return err < e;
+};
+
+fn veryclose(a: f64, b: f64) bool = tolerance(a, b, 4e-16);
+
+fn alike(a: f64, b: f64) bool = {
+ if (math::isnan(a) && math::isnan(b)) {
+ return true;
+ };
+ if (a == b) {
+ return math::signf64(a) == math::signf64(b);
+ };
+ return false;
+};
+
+fn csoclose(a: c128, b: c128, e: f64) bool = {
+ const d = absc128(subc128(a, b));
+ if (b.0 != 0f64 || b.1 != 0f64) {
+ e *= absc128(b);
+ if (e < 0f64) {
+ e = -e;
+ };
+ };
+ return d < e;
+};
+
+fn cveryclose(a: c128, b: c128) bool = csoclose(a, b, 4e-16);
+
+fn calike(a: c128, b: c128) bool = {
+ let realalike = false, imagalike = false;
+ realalike = if (isexact(b.0)) {
+ yield alike(a.0, b.0);
+ } else {
+ // Allow non-exact special cases to have errors in ULP.
+ yield veryclose(a.0, b.0);
+ };
+ imagalike = if (isexact(b.1)) {
+ yield alike(a.1, b.1);
+ } else {
+ // Allow non-exact special cases to have errors in ULP.
+ yield veryclose(a.1, b.1);
+ };
+ return realalike && imagalike;
+};
+
+// Special cases that should match exactly. Other cases are multiples of pi that
+// may not be last bit identical on all platforms.
+fn isexact(x: f64) bool =
+ math::isnan(x) || math::isinf(x) || x == 0f64 || x == 1f64 || x == -1f64;
+
+@test fn abs() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(veryclose(TEST_ABS[i], absc128(VC[i])));
+ };
+ for (let i = 0z; i < len(TEST_VCABSSC); i += 1) {
+ assert(alike(TEST_ABSSC[i], absc128(TEST_VCABSSC[i])));
+ };
+};
+
+@test fn acos() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ // XXX: should have 1e-14 precision
+ assert(csoclose(TEST_ACOS[i], acosc128(VC[i]), 1e-7));
+ };
+ for (let i = 0z; i < len(TEST_ACOSSC); i += 1) {
+ const v = TEST_ACOSSC[i];
+ assert(calike(v.1, acosc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // acos(conj(z)) == conj(acos(z))
+ assert(calike(conjc128(v.1), acosc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ };
+ for (let i = 0z; i < len(BRANCHPOINTS); i += 1) {
+ const pt = BRANCHPOINTS[i];
+ assert(cveryclose(acosc128(pt.0), acosc128(pt.1)));
+ };
+};
+
+@test fn acosh() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ // XXX: should have 1e-14 precision
+ assert(csoclose(TEST_ACOSH[i], acoshc128(VC[i]), 1e-7));
+ };
+ for (let i = 0z; i < len(TEST_ACOSHSC); i += 1) {
+ const v = TEST_ACOSHSC[i];
+ assert(calike(v.1, acoshc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // acosh(conj(z)) == conj(acosh(z))
+ assert(calike(conjc128(v.1), acoshc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ };
+ for (let i = 0z; i < len(BRANCHPOINTS); i += 1) {
+ const pt = BRANCHPOINTS[i];
+ assert(cveryclose(acoshc128(pt.0), acoshc128(pt.1)));
+ };
+};
+
+@test fn asin() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(csoclose(TEST_ASIN[i], asinc128(VC[i]), 1e-14));
+ };
+ for (let i = 0z; i < len(TEST_ASINSC); i += 1) {
+ const v = TEST_ASINSC[i];
+ assert(calike(v.1, asinc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // asin(conj(z)) == asin(sinh(z))
+ assert(calike(conjc128(v.1), asinc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ if (math::isnan(v.0.0) || math::isnan(v.1.0)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // asin(-z) == -asin(z)
+ assert(calike((-v.1.0, -v.1.1), asinc128((-v.0.0, -v.0.1)))
+ || calike(v.0, (-v.0.0, -v.0.1)));
+ };
+ for (let i = 0z; i < len(BRANCHPOINTS); i += 1) {
+ const pt = BRANCHPOINTS[i];
+ assert(cveryclose(asinc128(pt.0), asinc128(pt.1)));
+ };
+};
+
+@test fn asinh() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(csoclose(TEST_ASINH[i], asinhc128(VC[i]), 4e-15));
+ };
+ for (let i = 0z; i < len(TEST_ASINHSC); i += 1) {
+ const v = TEST_ASINHSC[i];
+ assert(calike(v.1, asinhc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // asinh(conj(z)) == asinh(sinh(z))
+ assert(calike(conjc128(v.1), asinhc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ if (math::isnan(v.0.0) || math::isnan(v.1.0)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // asinh(-z) == -asinh(z)
+ assert(calike((-v.1.0, -v.1.1), asinhc128((-v.0.0, -v.0.1)))
+ || calike(v.0, (-v.0.0, -v.0.1)));
+ };
+ for (let i = 0z; i < len(BRANCHPOINTS); i += 1) {
+ const pt = BRANCHPOINTS[i];
+ assert(cveryclose(asinhc128(pt.0), asinhc128(pt.1)));
+ };
+};
+
+@test fn conj() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(cveryclose(TEST_CONJ[i], conjc128(VC[i])));
+ };
+ for (let i = 0z; i < len(TEST_VCCONJSC); i += 1) {
+ assert(calike(TEST_CONJSC[i], conjc128(TEST_VCCONJSC[i])));
+ };
+};
+
+@test fn cos() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(csoclose(TEST_COS[i], cosc128(VC[i]), 3e-15));
+ };
+ for (let i = 0z; i < len(TEST_COSSC); i += 1) {
+ const v = TEST_COSSC[i];
+ assert(calike(v.1, cosc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // cos(conj(z)) == cos(cosh(z))
+ assert (calike(conjc128(v.1), cosc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ if (math::isnan(v.0.0) || math::isnan(v.1.0)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // cos(-z) == cos(z)
+ assert(calike(v.1, cosc128((-v.0.0, -v.0.1)))
+ || calike(v.0, (-v.0.0, -v.0.1)));
+ };
+};
+
+@test fn cosh() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(csoclose(TEST_COSH[i], coshc128(VC[i]), 2e-15));
+ };
+ for (let i = 0z; i < len(TEST_COSHSC); i += 1) {
+ const v = TEST_COSHSC[i];
+ assert(calike(v.1, coshc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // cosh(conj(z)) == conj(cosh(z))
+ assert(calike(conjc128(v.1), coshc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ if (math::isnan(v.0.0) || math::isnan(v.1.0)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // cosh(-z) == cosh(z)
+ assert(calike(v.1, coshc128((-v.0.0, -v.0.1)))
+ || calike(v.0, (-v.0.0, -v.0.1)));
+ };
+};
+
+@test fn exp() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(csoclose(TEST_EXP[i], expc128(VC[i]), 1e-15));
+ };
+ for (let i = 0z; i < len(TEST_EXPSC); i += 1) {
+ const v = TEST_EXPSC[i];
+ assert(calike(v.1, expc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // exp(conj(z)) == exp(cosh(z))
+ assert(calike(conjc128(v.1), expc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ };
+};
+
+@test fn isnan() void = {
+ for (let i = 0z; i < len(TEST_VCISNANSC); i += 1) {
+ assert(TEST_ISNANSC[i] == isnan(TEST_VCISNANSC[i]));
+ };
+};
+
+@test fn log() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(cveryclose(TEST_LOG[i], logc128(VC[i])));
+ };
+ for (let i = 0z; i < len(TEST_LOGSC); i += 1) {
+ const v = TEST_LOGSC[i];
+ assert(calike(v.1, logc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // log(conj(z)) == conj(log(z))
+ assert(calike(conjc128(v.1), logc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ };
+ for (let i = 0z; i < len(BRANCHPOINTS); i += 1) {
+ const pt = BRANCHPOINTS[i];
+ assert(cveryclose(logc128(pt.0), logc128(pt.1)));
+ };
+};
+
+@test fn polar() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ const p = polarc128(VC[i]);
+ assert(veryclose(TEST_POLAR[i].0, p.0)
+ || veryclose(TEST_POLAR[i].1, p.1));
+ };
+ for (let i = 0z; i < len(TEST_VCPOLARSC); i += 1) {
+ const p = polarc128(TEST_VCPOLARSC[i]);
+ assert(alike(TEST_POLARSC[i].0, p.0)
+ || alike(TEST_POLARSC[i].1, p.1));
+ };
+};
+
+@test fn pow() void = {
+ // Special cases for pow(0, c).
+ const zeropowers: [](c128, c128) = [
+ ((0f64, 0f64), (1f64, 0f64)),
+ ((1.5, 0f64), (0f64, 0f64)),
+ ((-1.5, 0f64), (math::INF, 0f64)),
+ ((-1.5, 1.5), (math::INF, math::INF)),
+ ];
+ for (let i = 0z; i < len(zeropowers); i += 1) {
+ const zp = zeropowers[i];
+ assert(equalc128(powc128((0f64, 0f64), zp.0), zp.1));
+ };
+ const a = (3f64, 3f64);
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(csoclose(TEST_POW[i], powc128(a, VC[i]), 4e-15));
+ };
+ for (let i = 0z; i < len(TEST_VCPOWSC); i += 1) {
+ const f = TEST_VCPOWSC[i];
+ assert(calike(TEST_POWSC[i], powc128(f.0, f.1)));
+ };
+ for (let i = 0z; i < len(BRANCHPOINTS); i += 1) {
+ const pt = BRANCHPOINTS[i];
+ assert(cveryclose(powc128(pt.0, (0.1, 0f64)),
+ powc128(pt.1, (0.1, 0f64))));
+ };
+};
+
+@test fn rect() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ const f = TEST_POLAR[i];
+ assert(cveryclose(VC[i], rectc128(f.0, f.1)));
+ };
+ for (let i = 0z; i < len(TEST_VCPOLARSC); i += 1) {
+ const f = TEST_POLARSC[i];
+ assert(calike(TEST_VCPOLARSC[i], rectc128(f.0, f.1)));
+ };
+};
+
+@test fn sin() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(csoclose(TEST_SIN[i], sinc128(VC[i]), 2e-15));
+ };
+ for (let i = 0z; i < len(TEST_SINSC); i += 1) {
+ const v = TEST_SINSC[i];
+ assert(calike(v.1, sinc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // sin(conj(z)) == conj(sin(z))
+ assert(calike(conjc128(sinc128(v.0)), sinc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ if (math::isnan(v.0.0) || math::isnan(v.1.0)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // sin(-z) == -sin(z)
+ assert(calike((-v.1.0, -v.1.1), sinc128((-v.0.0, -v.0.1)))
+ || calike(v.0, (-v.0.0, -v.0.1)));
+ };
+};
+
+@test fn sinh() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(csoclose(TEST_SINH[i], sinhc128(VC[i]), 2e-15));
+ };
+ for (let i = 0z; i < len(TEST_SINHSC); i += 1) {
+ const v = TEST_SINHSC[i];
+ assert(calike(v.1, sinhc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // sinh(conj(z)) == conj(sinh(z))
+ assert(calike(conjc128(v.1), sinhc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ if (math::isnan(v.0.0) || math::isnan(v.1.0)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // sinh(-z) == -sinh(z)
+ assert(calike((-v.1.0, -v.1.1), sinhc128((-v.0.0, -v.0.1)))
+ || calike(v.0, (-v.0.0, -v.0.1)));
+ };
+};
+
+@test fn sqrt() void = {
+ for (let i = 0z; i < len(VC); i += 1) {
+ assert(cveryclose(TEST_SQRT[i], sqrtc128(VC[i])));
+ };
+ for (let i = 0z; i < len(TEST_SQRTSC); i += 1) {
+ const v = TEST_SQRTSC[i];
+ assert(calike(v.1, sqrtc128(v.0)));
+ if (math::isnan(v.0.1) || math::isnan(v.1.1)) {
+ // Negating NaN is undefined with regard to the sign bit
+ // produced.
+ continue;
+ };
+ // sqrt(conj(z)) == conj(sqrt(z))
+ assert(calike(conjc128(v.1), sqrtc128(conjc128(v.0)))
+ || calike(v.0, conjc128(v.0)));
+ };
+ for (let i = 0z; i < len(BRANCHPOINTS); i += 1) {
+ const pt = BRANCHPOINTS[i];
+ assert(cveryclose(sqrtc128(pt.0), sqrtc128(pt.1)));
+ };
+};
diff --git a/math/complex/complex.ha b/math/complex/complex.ha
@@ -0,0 +1,394 @@
+// License: MPL-2.0
+// (c) 2022 Sebastian <sebastian@sebsite.pw>
+
+// Sections of the code below are based on Go's implementation, which is, in
+// turn, based on Cephes Math Library. The original C code can be found at
+// http://netlib.sandia.gov/cephes/c9x-complex/.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+//
+// The Go copyright notice:
+// ====================================================
+// Copyright (c) 2009 The Go Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// ====================================================
+
+use math;
+
+// A complex number containing a real component and an imaginary component,
+// represented as two single-precision floating point numbers.
+export type c64 = (f32, f32);
+
+// A complex number containing a real component and an imaginary component,
+// represented as two double-precision floating point numbers.
+export type c128 = (f64, f64);
+
+// A tagged union of all complex types.
+export type complex = (c64 | c128);
+
+// Converts a [[c64]] to a [[c128]].
+export fn c64to128(z: c64) c128 = (z.0: f64, z.1: f64);
+
+// Truncates a [[c128]] to a [[c64]]. Precision may be lost.
+export fn c128to64(z: c128) c64 = (z.0: f32, z.1: f32);
+
+// Adds two complex numbers.
+export fn addc128(a: c128, b: c128) c128 = (a.0 + b.0, a.1 + b.1);
+
+// Subtracts two complex numbers.
+export fn subc128(a: c128, b: c128) c128 = (a.0 - b.0, a.1 - b.1);
+
+// Multiplies two complex numbers.
+export fn mulc128(a: c128, b: c128) c128 =
+ (a.0 * b.0 - a.1 * b.1, a.1 * b.0 + a.0 * b.1);
+
+// Divides two complex numbers.
+export fn divc128(a: c128, b: c128) c128 = {
+ const denom = b.0 * b.0 + b.1 * b.1;
+ return (
+ (a.0 * b.0 + a.1 * b.1) / denom,
+ (a.1 * b.0 - a.0 * b.1) / denom,
+ );
+};
+
+// Takes the conjugate of a complex number by negating the imaginary component.
+export fn conjc64(z: c64) c64 = (z.0, -z.1);
+
+// Takes the conjugate of a complex number by negating the imaginary component.
+export fn conjc128(z: c128) c128 = (z.0, -z.1);
+
+// Takes the absolute value of a complex number.
+export fn absc128(z: c128) f64 = math::hypotf64(z.0, z.1);
+
+// Gets the argument, or phase, of a complex number.
+export fn argc128(z: c128) f64 = math::atan2f64(z.1, z.0);
+
+// Checks if two complex numbers are equal. Be sure to take floating point
+// round-off errors into account.
+export fn equalc64(a: c64, b: c64) bool = a.0 == b.0 && a.1 == b.1;
+
+// Checks if two complex numbers are equal. Be sure to take floating point
+// round-off errors into account.
+export fn equalc128(a: c128, b: c128) bool = a.0 == b.0 && a.1 == b.1;
+
+// Returns [[math::E]] raised to the power of z.
+export fn expc128(z: c128) c128 = {
+ if (math::isinf(z.0)) {
+ if (z.0 > 0f64 && z.1 == 0f64) {
+ return z;
+ };
+ if (math::isinf(z.1) || math::isnan(z.1)) {
+ if (z.0 < 0f64) {
+ return (0f64, math::copysignf64(0f64, z.1));
+ } else {
+ return (math::INF, math::NAN);
+ };
+ };
+ } else if (math::isnan(z.0) && z.1 == 0f64) {
+ return (math::NAN, z.1);
+ };
+ return rectc128(math::expf64(z.0), z.1);
+};
+
+// Returns true if the given complex number is infinite.
+export fn isinf(z: c128) bool = math::isinf(z.0) || math::isinf(z.1);
+
+// Returns true if the given complex number is NaN.
+export fn isnan(z: c128) bool =
+ !isinf(z) && (math::isnan(z.0) || math::isnan(z.1));
+
+// Returns the natural logarithm of z.
+export fn logc128(z: c128) c128 = (math::logf64(absc128(z)), argc128(z));
+
+// Negates z.
+export fn negc128(z: c128) c128 = (-z.0, -z.1);
+
+// Creates a new [[c128]] from the polar coordinates (r, theta).
+export fn rectc128(r: f64, theta: f64) c128 =
+ (r * math::cosf64(theta), r * math::sinf64(theta));
+
+// Returns the polar coordinates of z.
+export fn polarc128(z: c128) (f64, f64) = (absc128(z), argc128(z));
+
+// Returns a raised to the power of b.
+export fn powc128(a: c128, b: c128) c128 = {
+ if (a.0 == 0f64 && a.1 == 0f64) {
+ if (isnan(b)) {
+ return (math::NAN, math::NAN);
+ } else if (b.0 == 0f64) {
+ return (1f64, 0f64);
+ } else if (b.0 < 0f64) {
+ return (math::INF, if (b.1 == 0f64) 0f64 else math::INF);
+ } else {
+ assert(b.0 > 0f64);
+ return (0f64, 0f64);
+ };
+ };
+ const mod = absc128(a);
+ if (mod == 0f64) {
+ return (0f64, 0f64);
+ };
+ let r = math::powf64(mod, b.0);
+ const phase = argc128(a);
+ let theta = b.0 * phase;
+ if (b.1 != 0f64) {
+ r *= math::expf64(-b.1 * phase);
+ theta += b.1 * math::logf64(mod);
+ };
+ return rectc128(r, theta);
+};
+
+// Projects z onto the surface of a Riemann Sphere. If z is finite, it projects
+// to itself. If z is infinite, it projects to positive infinity on the real
+// axis.
+export fn projc128(z: c128) c128 =
+ if (!isinf(z)) z else (math::INF, math::copysignf64(0f64, z.1));
+
+// Returns the square root of z.
+export fn sqrtc128(z: c128) c128 = {
+ if (z.1 == 0f64) {
+ if (z.0 == 0f64) {
+ return (0f64, z.1);
+ };
+ if (z.0 < 0f64) {
+ return (0f64, math::copysignf64(math::sqrtf64(-z.0), z.1));
+ };
+ return (math::sqrtf64(z.0), z.1);
+ };
+ if (math::isinf(z.1)) {
+ return (math::INF, z.1);
+ };
+ if (z.0 == 0f64) {
+ if (z.1 < 0f64) {
+ const r = math::sqrtf64(-0.5 * z.1);
+ return (r, -r);
+ } else {
+ const r = math::sqrtf64(0.5 * z.1);
+ return (r, r);
+ };
+ };
+ let a = z.0, b = z.1;
+ const scale = if (math::absf64(a) > 4f64 || math::absf64(b) > 4f64) {
+ a *= 0.25;
+ b *= 0.25;
+ yield 2f64;
+ } else {
+ a *= 1.8014398509481984e16; // 2**54
+ b *= 1.8014398509481984e16;
+ yield 7.450580596923828125e-9; // 2**-27
+ };
+ let r = math::hypotf64(a, b);
+ const t = if (a > 0f64) {
+ const t = math::sqrtf64(0.5 * r + 0.5 * a);
+ r = scale * math::absf64(0.5 * b / t);
+ yield t * scale;
+ } else {
+ r = math::sqrtf64(0.5 * r - 0.5 * a);
+ const t = scale * math::absf64(0.5 * b / r);
+ r *= scale;
+ yield t;
+ };
+ return (t, if (b < 0f64) -r else r);
+};
+
+// Returns the sine of z, in radians.
+export fn sinc128(z: c128) c128 = {
+ if (z.1 == 0f64 && (math::isinf(z.0) || math::isnan(z.0))) {
+ return (math::NAN, z.1);
+ } else if (math::isinf(z.1)) {
+ if (z.0 == 0f64) {
+ return z;
+ } else if (math::isinf(z.0) || math::isnan(z.0)) {
+ return (math::NAN, z.1);
+ };
+ } else if (z.0 == 0f64 && math::isnan(z.1)) {
+ return z;
+ };
+ const shch = sinhcosh(z.1);
+ return (math::sinf64(z.0) * shch.1, math::cosf64(z.0) * shch.0);
+};
+
+// Returns the hyperbolic sine of z.
+export fn sinhc128(z: c128) c128 = {
+ if (z.0 == 0f64 && (math::isinf(z.1) || math::isnan(z.1))) {
+ return (z.0, math::NAN);
+ } else if (math::isinf(z.0)) {
+ if (z.1 == 0f64) {
+ return z;
+ } else if (math::isinf(z.1) || math::isnan(z.1)) {
+ return (z.0, math::NAN);
+ };
+ } else if (z.1 == 0f64 && math::isnan(z.0)) {
+ return (math::NAN, z.1);
+ };
+ const shch = sinhcosh(z.0);
+ return (math::cosf64(z.1) * shch.0, math::sinf64(z.1) * shch.1);
+};
+
+// Returns the arcsine, in radians, of z.
+export fn asinc128(z: c128) c128 = {
+ if (z.1 == 0f64 && math::absf64(z.0) <= 1f64) {
+ return (math::asinf64(z.0), z.1);
+ } else if (z.0 == 0f64 && math::absf64(z.1) <= 1f64) {
+ return (z.0, math::asinhf64(z.1));
+ } else if (math::isnan(z.1)) {
+ if (z.0 == 0f64) {
+ return (z.0, math::NAN);
+ } else if (math::isinf(z.0)) {
+ return (math::NAN, z.0);
+ } else {
+ return (math::NAN, math::NAN);
+ };
+ } else if (math::isinf(z.1)) {
+ if (math::isnan(z.0)) {
+ return z;
+ } else if (math::isinf(z.0)) {
+ return (math::copysignf64(math::PI / 4f64, z.0), z.1);
+ } else {
+ return (math::copysignf64(0f64, z.0), z.1);
+ };
+ } else if (math::isinf(z.0)) {
+ return (math::copysignf64(math::PI / 2f64, z.0),
+ math::copysignf64(z.0, z.1));
+ };
+ const ct = (-z.1, z.0); // i * z
+ const zz = mulc128(z, z);
+ const z1 = (1f64 - zz.0, -zz.1); // 1 - z * z
+ const z2 = sqrtc128(z1); // z2 = sqrt(1 - z * z)
+ const w = logc128(addc128(ct, z2));
+ return (w.1, -w.0); // -i * w
+};
+
+// Returns the inverse hyperbolic sine of z.
+export fn asinhc128(z: c128) c128 = {
+ if (z.1 == 0f64 && math::absf64(z.0) <= 1f64) {
+ return (math::asinhf64(z.0), z.1);
+ } else if (z.0 == 0f64 && math::absf64(z.1) <= 1f64) {
+ return (z.0, math::asinf64(z.1));
+ } else if (math::isinf(z.0)) {
+ if (math::isinf(z.1)) {
+ return (z.0, math::copysignf64(math::PI / 4f64, z.1));
+ } else if (math::isnan(z.1)) {
+ return z;
+ } else {
+ return (z.0, math::copysignf64(0f64, z.1));
+ };
+ } else if (math::isnan(z.0)) {
+ if (z.1 == 0f64) {
+ return z;
+ } else if (math::isinf(z.1)) {
+ return (z.1, z.0);
+ } else {
+ return (math::NAN, math::NAN);
+ };
+ } else if (math::isinf(z.1)) {
+ return (math::copysignf64(z.1, z.0),
+ math::copysign(math::PI / 2f64, z.1));
+ };
+ const zz = mulc128(z, z);
+ const z1 = (1f64 + zz.0, zz.1); // 1 + z * z
+ return logc128(addc128(z, sqrtc128(z1))); // log(x + sqrt(1 + x * x))
+};
+
+// Returns the cosine of z, in radians.
+export fn cosc128(z: c128) c128 = {
+ if (z.1 == 0f64 && (math::isinf(z.0) || math::isnan(z.0))) {
+ return (math::NAN, -z.1 * math::copysignf64(0f64, z.0));
+ } else if (math::isinf(z.1)) {
+ if (z.0 == 0f64) {
+ return (math::INF, -z.0 * math::copysignf64(0f64, z.1));
+ } else if (math::isinf(z.0) || math::isnan(z.0)) {
+ return (math::INF, math::NAN);
+ };
+ } else if (z.0 == 0f64 && math::isnan(z.1)) {
+ return (math::NAN, 0f64);
+ };
+ const shch = sinhcosh(z.1);
+ return (math::cosf64(z.0) * shch.1, -math::sinf64(z.0) * shch.0);
+};
+
+// Returns the hyperbolic cosine of z.
+export fn coshc128(z: c128) c128 = {
+ if (z.0 == 0f64 && (math::isinf(z.1) || math::isnan(z.1))) {
+ return (math::NAN, z.0 * math::copysignf64(0f64, z.1));
+ } else if (math::isinf(z.0)) {
+ if (z.1 == 0f64) {
+ return (math::INF, z.1 * math::copysignf64(0f64, z.0));
+ } else if (math::isinf(z.1) || math::isnan(z.1)) {
+ return (math::INF, math::NAN);
+ };
+ } else if (z.1 == 0f64 && math::isnan(z.0)) {
+ return (math::NAN, z.1);
+ };
+ const shch = sinhcosh(z.0);
+ return (math::cosf64(z.1) * shch.1, math::sinf64(z.1) * shch.0);
+};
+
+// Returns the arccosine, in radians, of z.
+export fn acosc128(z: c128) c128 = {
+ const w = asinc128(z);
+ return (math::PI / 2f64 - w.0, -w.1);
+};
+
+// Returns the inverse hyperbolic cosine of z.
+export fn acoshc128(z: c128) c128 = {
+ if (z.0 == 0f64 && z.1 == 0f64) {
+ return (0f64, math::copysignf64(math::PI / 2f64, z.1));
+ };
+ const w = acosc128(z);
+ if (w.1 <= 0f64) {
+ return (-w.1, w.0); // i * w
+ };
+ return (w.1, -w.0); // -i * w
+};
+
+fn sinhcosh(x: f64) (f64, f64) = {
+ if (math::absf64(x) <= 0.5) {
+ return (math::sinhf64(x), math::coshf64(x));
+ };
+ let e = math::expf64(x);
+ const ei = 0.5 / e;
+ e *= 0.5;
+ return (e - ei, e + ei);
+};
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -1064,6 +1064,22 @@ net_uri() {
ascii ip net::ip strconv strings strio
}
+gensrcs_math_complex() {
+ gen_srcs math::complex \
+ complex.ha \
+ $*
+}
+
+math_complex() {
+ if [ $testing -eq 0 ]
+ then
+ gensrcs_math_complex
+ else
+ gensrcs_math_complex \
+ +test.ha
+ fi
+ gen_ssa math::complex math
+}
math_random() {
gen_srcs math::random \
@@ -1439,6 +1455,7 @@ linux::timerfd linux
linux::vdso linux
log linux freebsd
math
+math::complex
math::random
net linux freebsd
net::dial
diff --git a/stdlib.mk b/stdlib.mk
@@ -502,6 +502,12 @@ stdlib_deps_any += $(stdlib_math_any)
stdlib_math_linux = $(stdlib_math_any)
stdlib_math_freebsd = $(stdlib_math_any)
+# gen_lib math::complex (any)
+stdlib_math_complex_any = $(HARECACHE)/math/complex/math_complex-any.o
+stdlib_deps_any += $(stdlib_math_complex_any)
+stdlib_math_complex_linux = $(stdlib_math_complex_any)
+stdlib_math_complex_freebsd = $(stdlib_math_complex_any)
+
# gen_lib math::random (any)
stdlib_math_random_any = $(HARECACHE)/math/random/math_random-any.o
stdlib_deps_any += $(stdlib_math_random_any)
@@ -1506,6 +1512,16 @@ $(HARECACHE)/math/math-any.ssa: $(stdlib_math_any_srcs) $(stdlib_rt) $(stdlib_ty
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nmath \
-t$(HARECACHE)/math/math.td $(stdlib_math_any_srcs)
+# math::complex (+any)
+stdlib_math_complex_any_srcs = \
+ $(STDLIB)/math/complex/complex.ha
+
+$(HARECACHE)/math/complex/math_complex-any.ssa: $(stdlib_math_complex_any_srcs) $(stdlib_rt) $(stdlib_math_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/math/complex
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nmath::complex \
+ -t$(HARECACHE)/math/complex/math_complex.td $(stdlib_math_complex_any_srcs)
+
# math::random (+any)
stdlib_math_random_any_srcs = \
$(STDLIB)/math/random/random.ha
@@ -2603,6 +2619,12 @@ testlib_deps_any += $(testlib_math_any)
testlib_math_linux = $(testlib_math_any)
testlib_math_freebsd = $(testlib_math_any)
+# gen_lib math::complex (any)
+testlib_math_complex_any = $(TESTCACHE)/math/complex/math_complex-any.o
+testlib_deps_any += $(testlib_math_complex_any)
+testlib_math_complex_linux = $(testlib_math_complex_any)
+testlib_math_complex_freebsd = $(testlib_math_complex_any)
+
# gen_lib math::random (any)
testlib_math_random_any = $(TESTCACHE)/math/random/math_random-any.o
testlib_deps_any += $(testlib_math_random_any)
@@ -3650,6 +3672,17 @@ $(TESTCACHE)/math/math-any.ssa: $(testlib_math_any_srcs) $(testlib_rt) $(testlib
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nmath \
-t$(TESTCACHE)/math/math.td $(testlib_math_any_srcs)
+# math::complex (+any)
+testlib_math_complex_any_srcs = \
+ $(STDLIB)/math/complex/complex.ha \
+ $(STDLIB)/math/complex/+test.ha
+
+$(TESTCACHE)/math/complex/math_complex-any.ssa: $(testlib_math_complex_any_srcs) $(testlib_rt) $(testlib_math_$(PLATFORM))
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/math/complex
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nmath::complex \
+ -t$(TESTCACHE)/math/complex/math_complex.td $(testlib_math_complex_any_srcs)
+
# math::random (+any)
testlib_math_random_any_srcs = \
$(STDLIB)/math/random/random.ha