numbers.scm 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. ;;; Bytevectors
  2. ;;; Copyright (C) 2024 Igalia, S.L.
  3. ;;;
  4. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  5. ;;; you may not use this file except in compliance with the License.
  6. ;;; You may obtain a copy of the License at
  7. ;;;
  8. ;;; http://www.apache.org/licenses/LICENSE-2.0
  9. ;;;
  10. ;;; Unless required by applicable law or agreed to in writing, software
  11. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  12. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ;;; See the License for the specific language governing permissions and
  14. ;;; limitations under the License.
  15. ;;; Commentary:
  16. ;;;
  17. ;;; Bytevectors.
  18. ;;;
  19. ;;; Code:
  20. (library (hoot numbers)
  21. (export + * - /
  22. < <= = >= >
  23. 1+ 1-
  24. abs
  25. floor
  26. ceiling
  27. round
  28. truncate
  29. number?
  30. complex?
  31. real?
  32. rational?
  33. integer?
  34. exact-integer?
  35. exact?
  36. inexact?
  37. finite?
  38. infinite?
  39. nan?
  40. inexact
  41. exact
  42. quotient
  43. remainder
  44. modulo
  45. even?
  46. odd?
  47. numerator
  48. denominator
  49. exact-integer-sqrt
  50. floor/
  51. floor-quotient
  52. floor-remainder
  53. ceiling/
  54. ceiling-quotient
  55. ceiling-remainder
  56. truncate/
  57. truncate-quotient
  58. truncate-remainder
  59. euclidean-quotient
  60. euclidean-remainder
  61. euclidean/
  62. gcd lcm
  63. max min
  64. negative?
  65. positive?
  66. zero?
  67. sin
  68. cos
  69. tan
  70. asin
  71. acos
  72. atan
  73. sqrt
  74. log
  75. exp
  76. rationalize
  77. square
  78. expt
  79. make-rectangular
  80. make-polar
  81. magnitude
  82. angle
  83. real-part
  84. imag-part
  85. most-positive-fixnum
  86. most-negative-fixnum)
  87. (import (only (hoot primitives)
  88. %+ %- %* %/
  89. %< %<= %= %>= %>
  90. %exact-integer? %complex? %real? %exact? %inexact? %integer?
  91. %rational? %number?
  92. %inexact
  93. %abs %floor %ceiling %sqrt
  94. %quotient %remainder %modulo
  95. %sin %cos %tan %asin %acos %atan
  96. %inline-wasm)
  97. (hoot apply)
  98. (hoot bitwise)
  99. (hoot eq)
  100. (hoot errors)
  101. (hoot match)
  102. (hoot not)
  103. (hoot syntax)
  104. (hoot values))
  105. (define (1+ x) (%+ x 1))
  106. (define (1- x) (%- x 1))
  107. (define-syntax-rule (define-associative-eta-expansion f %f)
  108. (define f
  109. (case-lambda
  110. (() (%f))
  111. ((x) (%f x))
  112. ((x y) (%f x y))
  113. ((x y . z) (apply f (%f x y) z)))))
  114. (define-associative-eta-expansion * %*)
  115. (define-associative-eta-expansion + %+)
  116. (define-syntax-rule (define-sub/div-eta-expansion f %f zero)
  117. (begin
  118. (define %generic
  119. (case-lambda
  120. ((y) (%f zero y))
  121. ((x y) (%f x y))
  122. ((x y . z) (apply %generic (%f x y) z))))
  123. (define-syntax f
  124. (lambda (stx)
  125. (syntax-case stx ()
  126. ((_ . x) #'(%f . x))
  127. (f (identifier? #'f) #'%generic))))))
  128. (define-sub/div-eta-expansion - %- 0)
  129. (define-sub/div-eta-expansion / %/ 1)
  130. (define-syntax-rule (define-comparison-expansion f %f)
  131. (begin
  132. (define %generic
  133. (case-lambda
  134. ((a b) (%f a b))
  135. ((a b . c)
  136. (let lp ((res (%f a b)) (a b) (c c))
  137. (match c
  138. (() res)
  139. ((b . c)
  140. (lp (and (%f a b) res) b c)))))))
  141. (define-syntax f
  142. (lambda (stx)
  143. (syntax-case stx ()
  144. ((_ x y . z) #'(%f x y . z))
  145. (f (identifier? #'f) #'%generic))))))
  146. (define-comparison-expansion < %<)
  147. (define-comparison-expansion <= %<=)
  148. (define-comparison-expansion = %=)
  149. (define-comparison-expansion >= %>=)
  150. (define-comparison-expansion > %>)
  151. (define (number? x) (%number? x))
  152. (define (complex? x) (%complex? x))
  153. (define (real? x) (%real? x))
  154. (define (rational? x) (%rational? x))
  155. (define (integer? x) (%integer? x))
  156. (define (exact-integer? x) (%exact-integer? x))
  157. (define (exact? x) (%exact? x))
  158. (define (inexact? x) (%inexact? x))
  159. (define (abs x) (%abs x))
  160. (define (floor x) (%floor x))
  161. (define (ceiling x) (%ceiling x))
  162. (define (round x) (%floor (+ x 0.5)))
  163. (define (truncate x)
  164. (check-type x real? 'truncate)
  165. (if (exact? x)
  166. (if (integer? x)
  167. x
  168. (truncate-quotient (numerator x) (denominator x)))
  169. (%inline-wasm
  170. '(func (param $x f64) (result f64)
  171. (f64.trunc (local.get $x)))
  172. x)))
  173. ;; Unlike R7RS, these only operate on real numbers.
  174. (define (infinite? x)
  175. (or (= x +inf.0) (= x -inf.0)))
  176. (define (nan? x)
  177. (not (= x x)))
  178. (define (finite? x)
  179. (and (not (infinite? x)) (not (nan? x))))
  180. (define (inexact x) (%inexact x))
  181. (define (exact x)
  182. (cond
  183. ((exact? x) x)
  184. (else
  185. (check-type x finite? 'exact)
  186. (call-with-values (lambda ()
  187. (%inline-wasm
  188. '(func (param $x f64)
  189. (result (ref eq) (ref eq))
  190. (call $f64->ratio (local.get $x)))
  191. x))
  192. (lambda (num denom) (/ num denom))))))
  193. (define (quotient x y) (%quotient x y))
  194. (define (remainder x y) (%remainder x y))
  195. (define (modulo x y) (%modulo x y))
  196. (define (even? x) (zero? (logand x 1)))
  197. (define (odd? x) (not (even? x)))
  198. (define (numerator x)
  199. (cond
  200. ((exact-integer? x) x)
  201. ((exact? x)
  202. (%inline-wasm
  203. '(func (param $x (ref $fraction))
  204. (result (ref eq))
  205. (struct.get $fraction $num (local.get $x)))
  206. x))
  207. (else (inexact (numerator (exact x))))))
  208. (define (denominator x)
  209. (cond
  210. ((exact-integer? x) 1)
  211. ((exact? x)
  212. (%inline-wasm
  213. '(func (param $x (ref $fraction))
  214. (result (ref eq))
  215. (struct.get $fraction $denom (local.get $x)))
  216. x))
  217. (else (inexact (denominator (exact x))))))
  218. (define (exact-integer-sqrt n)
  219. ;; FIXME: There's a compiler bug that makes this procedure return
  220. ;; junk when this exact-integer? check is enabled.
  221. ;;
  222. (check-type n exact-integer? 'exact-integer-sqrt)
  223. (assert (>= n 0) 'exact-integer-sqrt)
  224. (let loop ((x n) (y (quotient (+ n 1) 2)))
  225. (if (< y x)
  226. (loop y (quotient (+ y (quotient n y)) 2))
  227. (values x (- n (* x x))))))
  228. ;; Division operations adapted from SRFI-141 reference implementation.
  229. ;;
  230. ;; Copyright (c) 2010--2011 Taylor R. Campbell
  231. ;; All rights reserved.
  232. ;;
  233. ;; Redistribution and use in source and binary forms, with or without
  234. ;; modification, are permitted provided that the following conditions
  235. ;; are met:
  236. ;; 1. Redistributions of source code must retain the above copyright
  237. ;; notice, this list of conditions and the following disclaimer.
  238. ;; 2. Redistributions in binary form must reproduce the above copyright
  239. ;; notice, this list of conditions and the following disclaimer in the
  240. ;; documentation and/or other materials provided with the distribution.
  241. ;;
  242. ;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  243. ;; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  244. ;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  245. ;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  246. ;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  247. ;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  248. ;; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  249. ;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  250. ;; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  251. ;; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  252. ;; SUCH DAMAGE.
  253. (define (floor-/+ n d)
  254. (let ((n (- n)))
  255. (let ((q (quotient n d)) (r (remainder n d)))
  256. (if (zero? r)
  257. (values (- q) r)
  258. (values (1- (- q)) (- d r))))))
  259. (define (floor+/- n d)
  260. (let ((d (- d)))
  261. (let ((q (quotient n d)) (r (remainder n d)))
  262. (if (zero? r)
  263. (values (- q) r)
  264. (values (1- (- q)) (- r d))))))
  265. (define (floor/ n d)
  266. (if (and (exact-integer? n) (exact-integer? d))
  267. (cond
  268. ((and (negative? n) (negative? d))
  269. (let ((n (- n)) (d (- d)))
  270. (values (quotient n d) (- (remainder n d)))))
  271. ((negative? n) (floor-/+ n d))
  272. ((negative? d) (floor+/- n d))
  273. (else (values (quotient n d) (remainder n d))))
  274. (let ((q (floor (/ n d))))
  275. (values q (- n (* d q))))))
  276. (define (floor-quotient n d)
  277. (if (and (exact-integer? n) (exact-integer? d))
  278. (cond
  279. ((and (negative? n) (negative? d))
  280. (quotient (- n) (- d)))
  281. ((negative? n)
  282. (call-with-values (lambda () (floor-/+ n d))
  283. (lambda (q r) q)))
  284. ((negative? d)
  285. (call-with-values (lambda () (floor+/- n d))
  286. (lambda (q r) q)))
  287. (else (quotient n d)))
  288. (floor (/ n d))))
  289. (define (floor-remainder n d)
  290. (if (and (exact-integer? n) (exact-integer? d))
  291. (cond
  292. ((and (negative? n) (negative? d))
  293. (- (remainder (- n) (- d))))
  294. ((negative? n)
  295. (call-with-values (lambda () (floor-/+ n d))
  296. (lambda (q r) r)))
  297. ((negative? d)
  298. (call-with-values (lambda () (floor+/- n d))
  299. (lambda (q r) r)))
  300. (else (remainder n d)))
  301. (- n (* d (floor (/ n d))))))
  302. (define (ceiling-/- n d)
  303. (let ((n (- n)) (d (- d)))
  304. (let ((q (quotient n d)) (r (remainder n d)))
  305. (if (zero? r)
  306. (values q r)
  307. (values (1+ q) (- d r))))))
  308. (define (ceiling+/+ n d)
  309. (let ((q (quotient n d)) (r (remainder n d)))
  310. (if (zero? r)
  311. (values q r)
  312. (values (1+ q) (- r d)))))
  313. (define (ceiling/ n d)
  314. (if (and (exact-integer? n) (exact-integer? d))
  315. (cond
  316. ((and (negative? n) (negative? d))
  317. (ceiling-/- n d))
  318. ((negative? n)
  319. (let ((n (- n)))
  320. (values (- (quotient n d)) (- (remainder n d)))))
  321. ((negative? d)
  322. (let ((d (- d)))
  323. (values (- (quotient n d)) (remainder n d))))
  324. (else (ceiling+/+ n d)))
  325. (let ((q (ceiling (/ n d))))
  326. (values q (- n (* d q))))))
  327. (define (ceiling-quotient n d)
  328. (if (and (exact-integer? n) (exact-integer? d))
  329. (cond
  330. ((and (negative? n) (negative? d))
  331. (call-with-values (lambda () (ceiling-/- n d))
  332. (lambda (q r) q)))
  333. ((negative? n) (- (quotient (- n) d)))
  334. ((negative? d) (- (quotient n (- d))))
  335. (else
  336. (call-with-values (lambda () (ceiling+/+ n d))
  337. (lambda (q r) q))))
  338. (ceiling (/ n d))))
  339. (define (ceiling-remainder n d)
  340. (if (and (exact-integer? n) (exact-integer? d))
  341. (cond
  342. ((and (negative? n) (negative? d))
  343. (call-with-values (lambda () (ceiling-/- n d))
  344. (lambda (q r) r)))
  345. ((negative? n) (- (remainder (- n) d)))
  346. ((negative? d) (remainder n (- d)))
  347. (else
  348. (call-with-values (lambda () (ceiling+/+ n d))
  349. (lambda (q r) r))))
  350. (- n (* d (ceiling (/ n d))))))
  351. (define (truncate/ n d)
  352. (if (and (exact-integer? n) (exact-integer? d))
  353. (cond
  354. ((and (negative? n) (negative? d))
  355. (let ((n (- n)) (d (- d)))
  356. (values (quotient n d) (- (remainder n d)))))
  357. ((negative? n)
  358. (let ((n (- n)))
  359. (values (- (quotient n d)) (- (remainder n d)))))
  360. ((negative? d)
  361. (let ((d (- d)))
  362. (values (- (quotient n d)) (remainder n d))))
  363. (else
  364. (values (quotient n d) (remainder n d))))
  365. (let ((q (truncate (/ n d))))
  366. (values q (- n (* d q))))))
  367. (define (truncate-quotient n d)
  368. (if (and (exact-integer? n) (exact-integer? d))
  369. (cond
  370. ((and (negative? n) (negative? d)) (quotient (- n) (- d)))
  371. ((negative? n) (- (quotient (- n) d)))
  372. ((negative? d) (- (quotient n (- d))))
  373. (else (quotient n d)))
  374. (truncate (/ n d))))
  375. (define (truncate-remainder n d)
  376. (if (and (exact-integer? n) (exact-integer? d))
  377. (cond
  378. ((and (negative? n) (negative? d))
  379. (- (remainder (- n) (- d))))
  380. ((negative? n) (- (remainder (- n) d)))
  381. ((negative? d) (remainder n (- d)))
  382. (else (remainder n d)))
  383. (- n (* d (truncate (/ n d))))))
  384. (define (euclidean/ n d)
  385. (if (and (exact-integer? n) (exact-integer? d))
  386. (cond
  387. ((and (negative? n) (negative? d)) (ceiling-/- n d))
  388. ((negative? n) (floor-/+ n d))
  389. ((negative? d)
  390. (let ((d (- 0 d)))
  391. (values (- 0 (quotient n d)) (remainder n d))))
  392. (else (values (quotient n d) (remainder n d))))
  393. (let ((q (if (negative? d) (ceiling (/ n d)) (floor (/ n d)))))
  394. (values q (- n (* d q))))))
  395. (define (euclidean-quotient n d)
  396. (if (and (exact-integer? n) (exact-integer? d))
  397. (cond
  398. ((and (negative? n) (negative? d))
  399. (call-with-values (lambda () (ceiling-/- n d))
  400. (lambda (q r) q)))
  401. ((negative? n)
  402. (call-with-values (lambda () (floor-/+ n d))
  403. (lambda (q r) q)))
  404. ((negative? d) (- (quotient n (- d))))
  405. (else (quotient n d)))
  406. (if (negative? d) (ceiling (/ n d)) (floor (/ n d)))))
  407. (define (euclidean-remainder n d)
  408. (if (and (exact-integer? n) (exact-integer? d))
  409. (cond
  410. ((and (negative? n) (negative? d))
  411. (call-with-values (lambda () (ceiling-/- n d))
  412. (lambda (q r) r)))
  413. ((negative? n)
  414. (call-with-values (lambda () (floor-/+ n d))
  415. (lambda (q r) r)))
  416. ((negative? d) (remainder n (- d)))
  417. (else (remainder n d)))
  418. (- n (* d (if (negative? d) (ceiling (/ n d)) (floor (/ n d)))))))
  419. (define gcd
  420. (case-lambda
  421. (() 0)
  422. ((x)
  423. (check-type x integer? 'gcd)
  424. x)
  425. ((x y)
  426. (cond
  427. ((or (eq? x 0) (eq? y 0)) 0)
  428. ((and (exact-integer? x) (exact-integer? y))
  429. (/ (abs y) (denominator (/ x y))))
  430. (else
  431. (check-type x integer? 'gcd)
  432. (check-type y integer? 'gcd)
  433. (inexact (gcd (exact x) (exact y))))))
  434. ((x y . z)
  435. (apply gcd (gcd x y) z))))
  436. (define lcm
  437. (case-lambda
  438. (() 1)
  439. ((x)
  440. (check-type x integer? 'lcm)
  441. x)
  442. ((x y)
  443. (cond
  444. ((and (eq? x 0) (eq? y 0)) 0)
  445. ((and (exact-integer? x) (exact-integer? y))
  446. (quotient (abs (* x y)) (gcd x y)))
  447. (else
  448. (check-type x integer? 'lcm)
  449. (check-type y integer? 'lcm)
  450. (inexact (lcm (exact x) (exact y))))))
  451. ((x y . z)
  452. (apply lcm (lcm x y) z))))
  453. (define max
  454. (case-lambda
  455. ((x) x)
  456. ((x y) (if (> x y) x y))
  457. ((x y . z) (apply max (max x y) z))))
  458. (define min
  459. (case-lambda
  460. ((x) x)
  461. ((x y) (if (< x y) x y))
  462. ((x y . z) (apply min (min x y) z))))
  463. (define (negative? x) (< x 0))
  464. (define (positive? x) (> x 0))
  465. (define (zero? x) (= x 0))
  466. (define (sin x) (%sin x))
  467. (define (cos x) (%cos x))
  468. (define (tan x) (%tan x))
  469. (define (asin x) (%asin x))
  470. (define (acos x) (%acos x))
  471. (define atan
  472. (case-lambda
  473. ((x) (%atan x))
  474. ((x y) (%atan x y))))
  475. (define (sqrt x) (%sqrt x))
  476. (define* (log x #:optional y)
  477. (define (%log x)
  478. (check-type x real? 'log)
  479. (%inline-wasm
  480. '(func (param $x f64) (result (ref eq))
  481. (call $log (local.get $x)))
  482. (inexact x)))
  483. (if y
  484. (/ (%log x)
  485. (%log y))
  486. (%log x)))
  487. (define (exp x)
  488. (define (%exp x)
  489. (check-type x real? 'log)
  490. (%inline-wasm
  491. '(func (param $x f64) (result (ref eq))
  492. (call $exp (local.get $x)))
  493. (inexact x)))
  494. (%exp x))
  495. ;; Adapted from the comments for scm_rationalize in libguile's numbers.c
  496. (define (rationalize x y)
  497. (check-type x rational? 'rationalize)
  498. (check-type y rational? 'rationalize)
  499. (define (exact-rationalize x eps)
  500. (let ((n1 (if (negative? x) -1 1))
  501. (x (abs x))
  502. (eps (abs eps)))
  503. (let ((lo (- x eps))
  504. (hi (+ x eps)))
  505. (if (<= lo 0)
  506. 0
  507. (let loop ((nlo (numerator lo)) (dlo (denominator lo))
  508. (nhi (numerator hi)) (dhi (denominator hi))
  509. (n1 n1) (d1 0) (n2 0) (d2 1))
  510. (let-values (((qlo rlo) (floor/ nlo dlo))
  511. ((qhi rhi) (floor/ nhi dhi)))
  512. (let ((n0 (+ n2 (* n1 qlo)))
  513. (d0 (+ d2 (* d1 qlo))))
  514. (cond ((zero? rlo) (/ n0 d0))
  515. ((< qlo qhi) (/ (+ n0 n1) (+ d0 d1)))
  516. (else (loop dhi rhi dlo rlo n0 d0 n1 d1))))))))))
  517. (if (and (exact? x) (exact? y))
  518. (exact-rationalize x y)
  519. (inexact (exact-rationalize (exact x) (exact y)))))
  520. (define (square x) (* x x))
  521. (define (expt x y)
  522. (check-type x number? 'expt)
  523. (check-type y number? 'expt)
  524. (cond
  525. ((eqv? x 0)
  526. (cond ((zero? y) (if (exact? y) 1 1.0))
  527. ((positive? y) (if (exact? y) 0 0.0))
  528. (else +nan.0)))
  529. ((eqv? x 0.0)
  530. (cond ((zero? y) 1.0)
  531. ((positive? y) 0.0)
  532. (else +nan.0)))
  533. ((exact-integer? y)
  534. (if (< y 0)
  535. (/ 1 (expt x (abs y)))
  536. (let lp ((y y)
  537. (result 1))
  538. (if (= y 0)
  539. result
  540. (lp (1- y) (* x result))))))
  541. (else (exp (* y (log x))))))
  542. ;; (scheme complex)
  543. ;; Adapted from Guile's numbers.c
  544. (define (make-rectangular real imag)
  545. (check-type real real? 'make-rectangular)
  546. (check-type imag real? 'make-rectangular)
  547. (if (eq? imag 0)
  548. real
  549. (%inline-wasm
  550. '(func (param $real f64) (param $imag f64) (result (ref eq))
  551. (struct.new $complex
  552. (i32.const 0)
  553. (local.get $real)
  554. (local.get $imag)))
  555. (inexact real) (inexact imag))))
  556. (define (make-polar mag ang)
  557. (check-type mag real? 'make-polar)
  558. (check-type ang real? 'make-polar)
  559. (cond
  560. ((eq? mag 0) 0)
  561. ((eq? ang 0) mag)
  562. (else
  563. (%inline-wasm
  564. '(func (param $mag f64) (param $ang f64) (result (ref eq))
  565. (local $f0 f64) (local $f1 f64)
  566. (local.set $f0 (call $fcos (local.get $ang)))
  567. (local.set $f1 (call $fsin (local.get $ang)))
  568. ;; If sin/cos are NaN and magnitude is 0, return a complex
  569. ;; zero.
  570. (if (ref eq)
  571. (i32.and (call $f64-is-nan (local.get $f0))
  572. (call $f64-is-nan (local.get $f1))
  573. (f64.eq (local.get $mag) (f64.const 0.0)))
  574. (then (struct.new $complex
  575. (i32.const 0)
  576. (f64.const 0.0)
  577. (f64.const 0.0)))
  578. (else (struct.new $complex
  579. (i32.const 0)
  580. (f64.mul (local.get $mag) (local.get $f0))
  581. (f64.mul (local.get $mag) (local.get $f1))))))
  582. (inexact mag) (inexact ang)))))
  583. (define (magnitude z)
  584. (cond
  585. ((real? z) (abs z))
  586. (else
  587. (check-type z complex? 'magnitude)
  588. (let ((r (real-part z))
  589. (i (imag-part z)))
  590. (sqrt (+ (* r r) (* i i)))))))
  591. (define (angle z)
  592. (cond
  593. ((real? z)
  594. (if (negative? z)
  595. (atan 0.0 -1.0)
  596. 0.0))
  597. (else
  598. (check-type z complex? 'angle)
  599. (atan (imag-part z) (real-part z)))))
  600. (define (real-part z)
  601. (cond
  602. ((real? z) z)
  603. (else
  604. (check-type z complex? 'real-part)
  605. (%inline-wasm
  606. '(func (param $z (ref $complex)) (result f64)
  607. (struct.get $complex $real (local.get $z)))
  608. z))))
  609. (define (imag-part z)
  610. (cond
  611. ((real? z) 0.0)
  612. (else
  613. (check-type z complex? 'real-part)
  614. (%inline-wasm
  615. '(func (param $z (ref $complex)) (result f64)
  616. (struct.get $complex $imag (local.get $z)))
  617. z))))
  618. (define most-negative-fixnum (ash -1 29))
  619. (define most-positive-fixnum (- (ash 1 29) 1))
  620. )