Advertisement
Guest User

bigatom.e

a guest
Dec 20th, 2014
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 54.13 KB | None | 0 0
  1. -- -------------------------------------------------------------------------------------------
  2. -- Copyright (C) 2014 Carlos Gómez Andreu (cargoan)
  3. --
  4. -- This program is free software: you can redistribute it and/or modify
  5. -- it under the terms of the GNU General Public License as published by
  6. -- the Free Software Foundation, either version 3 of the License, or
  7. -- (at your option) any later version.
  8. --
  9. -- This program is distributed in the hope that it will be useful,
  10. -- but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. -- GNU General Public License for more details.
  13. --
  14. -- You should have received a copy of the GNU General Public License
  15. -- along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. -- -------------------------------------------------------------------------------------------
  17. --
  18. -- bigatom.e
  19. -- por Carlos J. Gómez Andreu (cargoan)
  20. --
  21. -- Mis números en coma flotante en base 10.
  22. --
  23. -- La función log() y relacionadas están adaptadas de bigfixedmath.e (Lucius L. Hilley III)
  24. -- del Archivo de Euphoria.
  25. -- Más precisa que la interna de euphoria y la que mejor ha ido con bigatoms.
  26. --
  27. -- La función exp() adaptada de las manpages de bc.
  28. --
  29. -- La función euler(), sobre el algoritmo no tengo ni idea, sacada de un ejemplo en Modula-2
  30. -- de un viejo compilador de Modula-Oberon que, muuucho tiempo ha, utilizaba en OS/2 llamado
  31. -- XDS. El algoritmo original fué escrito en Algol por Serge Batalov, reescrito en Modula-2
  32. -- y modificado por Eugene Nalimov y Pavel Zemtsov.
  33. -- Adaptado a Euphoria por mí (sin límite de decimales).
  34. --
  35. -- -------------------------------------------------------------------------------------------
  36. --
  37. -- Un bigatom es una sequence de tres elementos, el signo, el exponente y la mantisa.
  38. -- El signo es 1 si el número es positivo, -1 si es negativo ó 0 si es cero.
  39. --
  40. -- El valor de un bigatom se evalúa en la forma:
  41. -- valor = signo * mantisa * 10^exponente
  42. -- El punto decimal va implícito tras el primer dígito de la mantisa.
  43. --
  44. -- Un mismo valor puede tener diferentes representaciones.
  45. -- ej. el número -23.456 quedaría representado así:
  46. -- { -1, 1, {2, 3, 4, 5, 6} } = -1 * 2.3456 * 10^1
  47. -- o así:
  48. -- { -1, 3, {0, 0, 2, 3, 4, 5, 6} } = -1 * 0.023456 * 10^3
  49. -- también así:
  50. -- { -1, 1, {2, 3, 4, 5, 6, 0, 0} } = -1 * 2.345600 * 10^1
  51. -- etc.
  52. --
  53. -- Reduciéndose siempre a la forma más corta y almacenando únicamente los dígitos
  54. -- significativos del número; eliminando los ceros a derecha e izquierda hasta el
  55. -- primer dígito distinto de cero y ajustando el exponente en consecuencia.
  56. --
  57. -- La función normalize() es la encargada de realizar esta tarea.
  58. --
  59. -- -------------------------------------------------------------------------------------------
  60.  
  61. namespace bigatom
  62.  
  63. without warning &= { override }
  64. without type_check
  65.  
  66. -- -------------------------------------------------------------------------------------------
  67.  
  68. -- máximo número de dígitos de un atom (para conversión binario => decimal)
  69. ifdef BITS64 then
  70. constant ATOM_DIGS = 19 -- entre 18 y 20 más o menos (a gusto de cada uno)
  71. elsedef
  72. constant ATOM_DIGS = 15 -- ??? (no sé si en 32 bits sean más)
  73. end ifdef
  74.  
  75.  
  76. -- estructura de un bigatom
  77. public enum SIGN, EXPONENT, DIGITS
  78. --
  79. public type bigatom(object x)
  80. if length(x) = DIGITS
  81. and t_digits(x[DIGITS])
  82. and t_sign(x[SIGN])
  83. and integer(x[EXPONENT])
  84. then
  85. return 1
  86. end if
  87.  
  88. return 0
  89. end type
  90. --
  91.  
  92.  
  93. --
  94. constant tdigits = {0,1,2,3,4,5,6,7,8,9}
  95. --
  96. type t_digits(object x)
  97. if sequence(x) then
  98. for i = 1 to length(x) do
  99. if not find(x[i], tdigits) then
  100. return 0
  101. end if
  102. end for
  103. return 1
  104. end if
  105. return 0
  106. end type
  107. --
  108.  
  109.  
  110. -- signos válidos
  111. type enum t_sign
  112. SG_NOVALUE = -2,
  113. SG_MINUS,
  114. SG_ZERO,
  115. SG_PLUS
  116. end type
  117. --
  118.  
  119.  
  120. -- -------------------------------------------------------------------------------------------
  121.  
  122.  
  123. -- escala
  124. integer SCALE = 25 -- nº de decimales (posiciones o dígitos)
  125. integer SC_MODE = 1 -- 0 son posiciones, no 0 son dígitos
  126.  
  127. -- NO_VALUE: no es un número real.
  128. -- devuelto cuando un resultado es indefinido, indeterminado, un complejo, ...
  129. -- ej. división por cero, logaritmo de cero o negativo, raíz de un negativo, ...
  130. constant NO_VALUE = {SG_NOVALUE, 0, {}}
  131.  
  132. -- definición del cero
  133. constant ZERO = {SG_ZERO, -1, {}} -- ZERO = normalize({0,0,{0}})
  134. -- de utilidad en
  135. constant ONE = {SG_PLUS, 0, {1}} -- ONE = ba_new(1)
  136. --constant TWO = {SG_PLUS, 0, {2}} -- TWO = ba_new(2)
  137.  
  138. -- caracteres permitidos en la entrada
  139. constant SPACE = ' ' -- carácter espacio
  140. constant UNDERLINE = '_' -- carácter subrayado
  141.  
  142. -- caracteres signos
  143. constant SPLUS = '+' -- carácter signo positivo
  144. constant SMINUS = '-' -- carácter signo negativo
  145. constant SZERO = SPACE -- carácter signo de cero
  146.  
  147. integer DFCHAR = SPACE -- carácter de relleno decimales (formato 'c')
  148.  
  149.  
  150. -- -------------------------------------------------------------------------------------------
  151.  
  152.  
  153. --
  154. -- Establece el número de decimales y el modo (posiciones o dígitos)
  155. -- decs: (atom) el número de decimales
  156. -- (sequence) si es nula, devuelve los valores actuales
  157. -- si no, el primer elemento es el número de decimales
  158. -- y el segundo, si existe, es el modo
  159. --
  160. -- mode: si es cero, establece que son posiciones a partir del punto decimal
  161. -- mayor que cero, dígitos (si 0 < n < 1 no cuenta ceros delanteros) esto permite
  162. -- manejar números muy pequeños sin tener que usar una escala muy grande
  163. -- menor que cero, mantiene el modo anterior
  164. --
  165. -- Devuelve una sequence con los valores anteriores: { escala, modo }
  166. --
  167. export function scale(object decs = -1, integer mode = -1)
  168.  
  169. if sequence(decs) then
  170. if length(decs) then
  171. if length(decs) > 1 then
  172. mode = not (not decs[2])
  173. end if
  174. decs = decs[1]
  175. else
  176. decs = -1
  177. mode = -1
  178. end if
  179. end if
  180.  
  181. sequence prev = {SCALE, SC_MODE}
  182. if decs >= 0 then
  183. SCALE = floor(decs)
  184. end if
  185. if mode >= 0 then
  186. SC_MODE = not (not mode)
  187. end if
  188.  
  189. return prev
  190. end function
  191. --
  192.  
  193.  
  194. --
  195. -- Devuelve la escala de un bigatom
  196. -- (el número de decimales)
  197. --
  198. export function scale_of(bigatom N)
  199. integer decs = length(N[DIGITS]) - N[EXPONENT] - 1
  200. return decs * (decs > 0)
  201. end function
  202. --
  203.  
  204.  
  205. --
  206. -- Devuelve un bigatom con el valor de un número entero, un atom o, mejor aún,
  207. -- una cadena con la representación de un número en coma fija o flotante que
  208. -- no tiene pérdida de precisión por la conversión binario <=> decimal.
  209. --
  210. -- Permite el uso de separadores (espacio y subrayado) en la cadena para mejorar
  211. -- la legibilidad... o puede que no.
  212. -- Ej.: s = ba_new(1.2345) -- s = {1,1,{1,2,3,4,5}}
  213. -- s = ba_new("1 234 567.891_123") -- s = {1,6,{1,2,3,4,5,6,7,8,9,1,1,2,3}}
  214. -- s = ba_new("-.2_3 45e-1 _3") -- s = {-1,-14,{2,3,4,5}}
  215. --
  216. -- Devuelve NO_VALUE si la cadena es nula o no empieza con una representación de un
  217. -- número válida. Ej.:
  218. -- s = ba_new("e-231.2345 hola") -- s = {-2,0,{}} = NO_VALUE
  219. -- s = ba_new("-231.2345hola") -- s = {-1,2,{2,3,1,2,3,4,5}}
  220. -- s = ba_new("-231.2345e-23hola") -- s = {1,-21,{2,3,1,2,3,4,5}}
  221. -- s = ba_new("__ -231.2345 e-12e++..--Eholae") -- s = {1,-10,{2,3,1,2,3,4,5}}
  222. --
  223. export function ba_new(object number)
  224.  
  225. if bigatom(number) then
  226. return number
  227. elsif atom(number) then
  228. if integer(number) then
  229. return int_to_bigatom(number)
  230. end if
  231.  
  232. atom absn = number
  233. if absn < 0 then
  234. absn = -absn
  235. end if
  236.  
  237. integer exp, len, ndigits
  238. -- ndigits = -floor(-logb(absn), 10)
  239. ndigits = -floor(-eu:log(absn)/eu:log(10)) -- suficiente
  240. if ndigits >= 0 then
  241. if ndigits > ATOM_DIGS then
  242. ndigits = ATOM_DIGS
  243. end if
  244. number = sprintf(sprintf("%%+.%df", ATOM_DIGS - ndigits), number)
  245. len = find('.', number)
  246. if not len then
  247. len = length(number) - 1
  248. end if
  249. if len > ATOM_DIGS then
  250. number = int_value(number[1..ATOM_DIGS + 1])
  251. number = sprintf("%+.f", number)
  252. number &= repeat('0', len - length(number) + 1)
  253. end if
  254. else
  255. sequence snum = sprintf("%.e", number)
  256. exp = find('e', snum)
  257. if exp then
  258. exp = int_value(snum[exp+1..$])
  259. end if
  260. number = sprintf(sprintf("%%+.%df", ATOM_DIGS - exp), number)
  261. end if
  262. end if
  263.  
  264. sequence big = NO_VALUE
  265.  
  266. -- elimina separadores válidos (espacio y subrayado)
  267. -- se detiene con el primer carácter no válido y descarta el resto
  268. object c
  269. integer pos = 0, sflag = 0
  270. for i = 1 to length(number) do
  271. c = number[i]
  272. if integer(c) then
  273. if find(c, "+-") then
  274. if sflag then
  275. exit
  276. end if
  277. pos += 1
  278. number[pos] = c
  279. sflag = 1
  280. elsif find(c, ".0123456789eE") then
  281. pos += 1
  282. number[pos] = c
  283. elsif c = SPACE or c = UNDERLINE then
  284. continue
  285. else
  286. exit
  287. end if
  288. else
  289. exit
  290. end if
  291. end for
  292. if pos then
  293. while pos and find(number[pos], "+-.eE") do
  294. pos -= 1
  295. end while
  296. end if
  297. number = number[1..pos] -- remove(number, pos+1, length(number))
  298.  
  299. -- coma flotante
  300. pos = find('e', number) + find('E', number)
  301. if pos then
  302. big = ba_new(number[1..pos-1])
  303. big[EXPONENT] += int_value(number[pos+1..$])
  304.  
  305. return normalize(big)
  306. end if
  307.  
  308. -- coma fija
  309. if length(number) then
  310. if number[1] = SMINUS then
  311. big[SIGN] = SG_MINUS
  312. number = remove(number, 1)
  313. else
  314. big[SIGN] = SG_PLUS
  315. if number[1] = SPLUS then
  316. number = remove(number, 1)
  317. end if
  318. end if
  319.  
  320. pos = find('.', number)
  321. if pos then
  322. number = remove(number, pos)
  323. big[EXPONENT] = pos - 2
  324. else
  325. big[EXPONENT] = length(number) - 1
  326. end if
  327. big[DIGITS] = number - '0'
  328. end if
  329.  
  330. return normalize(big)
  331. end function
  332. --
  333.  
  334.  
  335. --
  336. -- Compara dos bigatoms
  337. -- (NO_VALUE es menor que cualquier número)
  338. --
  339. export function ba_compare(bigatom A, bigatom B)
  340. integer cmp = compare(A, B)
  341.  
  342. if A[SIGN] = SG_MINUS and B[SIGN] = SG_MINUS then
  343. cmp = -cmp
  344. end if
  345.  
  346. return cmp
  347. end function
  348. --
  349.  
  350.  
  351. -- -------------------------------------------------------------------------------------------
  352.  
  353.  
  354. --
  355. -- ###############################
  356. -- ### FUNCIONES DE SALIDA ###
  357. -- ###############################
  358. --
  359.  
  360. --
  361. -- Devuelve la representación completa de un bigatom en una cadena
  362. --
  363. export function ba_sprint(bigatom N)
  364. sequence str = to_string(N)
  365. if str[1] = SZERO then
  366. str = remove(str, 1)
  367. end if
  368.  
  369. return str
  370. end function
  371. --
  372.  
  373.  
  374. --
  375. -- Escribe la representación completa de un bigatom en un archivo
  376. -- (1 = STDOUT, 2 = STDERR)
  377. export procedure ba_print(integer file, bigatom N)
  378. puts(file, ba_sprint(N))
  379. end procedure
  380. --
  381.  
  382.  
  383. --
  384. -- Devuelve una cadena con la representación con formato de un bigatom
  385. -- Nota: Necesita una revisión a fondo, está hecha sobre la marcha pero es funcional.
  386. -- Sería bueno integrarla con otros tipos, substituir los bigatoms y pasarle todo
  387. -- a printf o sprintf. En realidad esta función solo lee la cadena de formato y
  388. -- llama a to_string() que es quien realiza la conversión del número y ésta ajusta
  389. -- al tamaño, pone el relleno.
  390. --
  391. -- La cadena de formato está formada por tres partes: la cabecera (el texto que va delante
  392. -- del número), el propio formato y la cola (el texto que se pondrá detrás). Todas opcionales.
  393. --
  394. -- Si la cadena es nula, se representará el número con todos sus dígitos. Si no, el formato se
  395. -- se delimita con la pareja de caracteres '%' y 'B'. La parte anterior y posterior al formato
  396. -- se añaden delante y detrás respectivamente. Si no contiene un formato %B, la cadena se coloca
  397. -- delante del número.
  398. --
  399. -- Es similar a printf(), las diferencias son:
  400. -- - El tamaño se refiere solo a la parte entera, no al total. Si delante del tamaño hay un
  401. -- carácter que no sea un dígito entre 1 y 9 o el signo, se toma como carácter de relleno
  402. -- para completar la parte entera.
  403. --
  404. -- - Si detrás del punto hay un cero, se pondrá el signo si el número no es cero, pero sí en
  405. -- la representación.
  406. --
  407. -- - Si el formato finaliza en 'a' se rellenan con ceros las posiciones decimales no ocupadas.
  408. -- Si finaliza en 'c' se utilizan espacios pero si va precedido de un carácter que no sea
  409. -- un dígito, se utiliza éste para rellenar las posiciones decimales.
  410. --
  411. -- 'a' y 'c' se usan principalmente para producir salidas encolumnadas.
  412. -- 'c' aumenta notablemente la legibilidad al poner solo los decimales necesarios. Si no se
  413. -- especifica un tamaño 'c' es ignorado. No así 'a'.
  414. --
  415. --
  416. -- fmt = '%' ['+'] [fchar] [size] [['.'] ['0'] [decs] ['a' | [char] 'c']] 'B'
  417. --
  418. -- [+] poner signo siempre (*)
  419. --
  420. -- [fchar] carácter de relleno (cualquiera excepto dígitos del 1 al 9, sí el 0)
  421. --
  422. -- [size] tamaño mínimo de la parte entera del número (si no cabe es ignorado)
  423. --
  424. -- [.] un punto, tan solo separa las partes de la cadena de formato
  425. --
  426. -- [0] poner signo cuando el número es menor que los límites de representación pero
  427. -- no cero en la escala actual, resultando ceros con signo
  428. --
  429. -- [decs] el número "máximo" de decimales a mostrar (si es negativo, todos los decimales)
  430. --
  431. -- [a|[char]c] 'a': rellenar con ceros las posiciones decimales no ocupadas.
  432. -- 'c': usa el carácter que le precede (si no es un dígito), o un espacio como
  433. -- carácter de relleno para la parte decimal. Si no se ha especificado un
  434. -- tamaño 'c' es ignorado.
  435. --
  436. -- Cuando el carácter de relleno es '0' se reserva la primera posición para el signo.
  437. --
  438. -- (*) El signo de cero (un espacio) solo se muestra cuando el carácter de relleno es '0' y
  439. -- el signo se coloca delante del relleno y no detrás como en los demás casos.
  440. --
  441. export function ba_sprintf(sequence fmt, bigatom N)
  442.  
  443. if not length(fmt) then
  444. return ba_sprint(N)
  445. end if
  446.  
  447. sequence head, tail
  448. integer fpos = find('%', fmt)
  449. if fpos then
  450. head = fmt[1..fpos-1]
  451. fmt = remove(fmt, 1, fpos)
  452. fpos = find('B', fmt)
  453. if fpos then
  454. tail = fmt[fpos+1..$]
  455. fmt = fmt[1..fpos-1]
  456. else
  457. tail = fmt
  458. fmt = ""
  459. end if
  460. else
  461. head = fmt
  462. fmt = ""
  463. tail = ""
  464. end if
  465.  
  466. sequence ifmt, dfmt
  467. integer decs = -1, dp = find('.', fmt)
  468. if dp then
  469. ifmt = fmt[1..dp-1]
  470. dfmt = fmt[dp+1..$]
  471. decs = 0
  472. else
  473. ifmt = fmt
  474. dfmt = ""
  475. end if
  476.  
  477. integer c, sg = 0, size = 0, fill = 0, fchar = SPACE
  478. while length(ifmt) do
  479. c = ifmt[1]
  480. if not sg and c = SPLUS then
  481. sg = 1
  482. elsif c < '1' or c > '9' then
  483. if fchar = SPACE then
  484. fchar = c
  485. end if
  486. else
  487. size = int_value(ifmt)
  488. exit
  489. end if
  490. ifmt = remove(ifmt, 1)
  491. end while
  492.  
  493. integer zsign = 0, all = 0
  494. if length(dfmt) then
  495. c = dfmt[$]
  496. if c = 'a' then
  497. all = 1
  498. elsif c = 'c' then
  499. c = dfmt[$-1]
  500. if size then
  501. all = 2
  502. if c < '0' or c > '9' then
  503. DFCHAR = c
  504. dfmt = dfmt[1..$-1]
  505. else
  506. DFCHAR = SPACE
  507. end if
  508. end if
  509. end if
  510. if all then
  511. dfmt = dfmt[1..$-1]
  512. end if
  513.  
  514. while length(dfmt) do
  515. c = dfmt[1]
  516. if not zsign and c = '0' then
  517. zsign = 1
  518. else
  519. decs = int_value(dfmt)
  520. exit
  521. end if
  522. dfmt = remove(dfmt, 1)
  523. end while
  524. end if
  525.  
  526. if decs < 0 then
  527. decs = scale_of(N)
  528. end if
  529.  
  530. sequence str = to_string(N, sg, decs, zsign, all)
  531.  
  532. -- elimina el signo de cero si el relleno no es cero
  533. if str[1] = SZERO and fchar != '0' then
  534. if size then
  535. str[1] = fchar
  536. else -- if not sg and fchar != SPACE then
  537. str = remove(str, 1)
  538. end if
  539. elsif str[1] = '<' and size and all then
  540. if all > 1 then -- 'c'
  541. str = str & repeat(DFCHAR, decs + 1)
  542. else -- 'a' (usa relleno parte entera)
  543. str = str & repeat(fchar, decs + 1)
  544. end if
  545. end if
  546.  
  547. -- si no hay decimales, substituye el punto por el relleno
  548. integer len = find('.', str)
  549. if len and str[len + 1] = DFCHAR then
  550. str[len] = DFCHAR
  551. end if
  552.  
  553. if len then
  554. decs = length(str) - len
  555. len -= 1
  556. else
  557. len = length(str)
  558. decs = 0
  559. end if
  560.  
  561. -- relleno parte entera
  562. len = size - len - decs - (decs > 0)
  563. if len > 0 then
  564. if fchar = '0' and str[1] != '<' then
  565. str = str[1] & repeat(fchar, len) & str[2..$]
  566. elsif str[1] = '<' then
  567. str = repeat(DFCHAR, len) & str
  568. else
  569. str = repeat(fchar, len) & str
  570. end if
  571. end if
  572.  
  573. return head & str & tail
  574. end function
  575. --
  576.  
  577.  
  578. --
  579. -- Escribe la representación con formato de un bigatom en un archivo
  580. -- (1 = STDOUT, 2 = STDERR)
  581. --
  582. export procedure ba_printf(integer file, sequence fmt, bigatom N)
  583. puts(file, ba_sprintf(fmt, N))
  584. end procedure
  585. --
  586.  
  587. -- -------------------------------------------------------------------------------------------
  588.  
  589.  
  590. -- ###################################
  591. -- ### OPERACIONES ARITMÉTICAS ###
  592. -- ###################################
  593.  
  594.  
  595. --
  596. -- Devuelve un bigatom con el resultado de la suma de dos números.
  597. --
  598. -- Admite atoms, bigatoms y representación de números en una cadena
  599. --
  600. export function ba_add(object A, object B)
  601.  
  602. if not bigatom(A) then
  603. A = ba_new(A)
  604. end if
  605. if not bigatom(B) then
  606. B = ba_new(B)
  607. end if
  608.  
  609. integer signA = A[SIGN], signB = B[SIGN]
  610. if signA = SG_ZERO then
  611. return B
  612. elsif signB = SG_ZERO then
  613. return A
  614. elsif signA = SG_NOVALUE or signB = SG_NOVALUE then
  615. return NO_VALUE
  616. end if
  617.  
  618. integer sign = SG_PLUS
  619. if signA = signB then
  620. sign = signA
  621. elsif signA = SG_MINUS then
  622. A[SIGN] = SG_PLUS
  623. return ba_sub(B, A)
  624. else
  625. B[SIGN] = SG_PLUS
  626. return ba_sub(A, B)
  627. end if
  628.  
  629. {A, B} = align(A, B)
  630.  
  631. integer exponent = A[EXPONENT]
  632. sequence res = digits_add(A[DIGITS], B[DIGITS])
  633. if res[1] then
  634. exponent += 1
  635. end if
  636. res = {sign, exponent, res[2]}
  637.  
  638. return normalize(res)
  639. end function
  640. --
  641.  
  642.  
  643. --
  644. -- Devuelve un bigatom con el resultado de la resta de dos números.
  645. --
  646. -- Admite atoms, bigatoms y representación de números en una cadena
  647. --
  648. export function ba_sub(object A, object B)
  649.  
  650. if not bigatom(A) then
  651. A = ba_new(A)
  652. end if
  653. if not bigatom(B) then
  654. B = ba_new(B)
  655. end if
  656.  
  657. integer signA = A[SIGN], signB = B[SIGN]
  658. if signA = SG_ZERO then
  659. B[SIGN] = -signB
  660. return B
  661. elsif signB = SG_ZERO then
  662. return A
  663. elsif signA = SG_NOVALUE or B[SIGN] = SG_NOVALUE then
  664. return NO_VALUE
  665. end if
  666.  
  667. if signA = SG_MINUS or signB = SG_MINUS then
  668. B[SIGN] = -signB
  669. return ba_add(A, B)
  670. end if
  671.  
  672. {A, B} = align(A, B)
  673.  
  674. sequence res = digits_sub(A[DIGITS], B[DIGITS])
  675. integer sign = SG_PLUS
  676. if res[1] then
  677. sign = SG_MINUS
  678. end if
  679. res = normalize({sign, A[EXPONENT], res[2]})
  680.  
  681. return res
  682. end function
  683. --
  684.  
  685.  
  686. --
  687. -- Devuelve un bigatom con el resultado de la multiplicación de dos números.
  688. --
  689. -- Admite atoms, bigatoms y representación de números en una cadena
  690. --
  691. export function ba_multiply(object A, object B, integer round = 0)
  692.  
  693. if not bigatom(A) then
  694. A = ba_new(A)
  695. end if
  696. if not bigatom(B) then
  697. B = ba_new(B)
  698. end if
  699.  
  700. integer signA = A[SIGN], signB = B[SIGN]
  701. integer signR = signA * signB
  702. if signA = SG_ZERO or signB = SG_ZERO then
  703. return ZERO
  704. elsif signA = SG_NOVALUE or signB = SG_NOVALUE then
  705. return NO_VALUE
  706. end if
  707.  
  708. sequence res, digsA = A[DIGITS], digsB = B[DIGITS]
  709. integer expA = A[EXPONENT], expB = B[EXPONENT], expR = expA + expB
  710. if equal({1}, digsA) then -- múltiplo de 10
  711. res = {signR, expR, digsB}
  712. elsif equal({1}, digsB) then -- múltiplo de 10
  713. res = {signR, expR, digsA}
  714. else
  715. res = digits_multiply(digsA, digsB)
  716. res = {signR, expR + (res[1] > 0), res[2]}
  717. end if
  718.  
  719. -- límite decimales
  720. integer ndecs
  721. if SC_MODE and res[EXPONENT] < 0 then
  722. ndecs = SCALE + 1
  723. else
  724. ndecs = res[EXPONENT] + SCALE + 2
  725. end if
  726. if ndecs > 0 then
  727. if round then
  728. res = round_digits(res, ndecs)
  729. else
  730. res[DIGITS] = remove(res[DIGITS], ndecs, length(res[DIGITS]))
  731. res = normalize(res)
  732. end if
  733. else
  734. res = ZERO
  735. end if
  736.  
  737. return res
  738. end function
  739. --
  740.  
  741.  
  742. --
  743. -- Devuelve el resultado de la división entera de dos números.
  744. --
  745. -- Admite atoms, bigatoms y representación de números en una cadena
  746. --
  747. -- los números son truncados antes de hacer la división
  748. --
  749. export function ba_idivide(object A, object B)
  750.  
  751. if not bigatom(A) then
  752. A = ba_trunc(ba_new(A))
  753. end if
  754. if not bigatom(B) then
  755. B = ba_trunc(ba_new(B))
  756. end if
  757.  
  758. integer signA = A[SIGN], signB = B[SIGN]
  759. if signB = SG_ZERO or
  760. signB = SG_NOVALUE or
  761. signA = SG_NOVALUE
  762. then
  763. return NO_VALUE
  764. elsif signA = SG_ZERO then
  765. return ZERO
  766. end if
  767.  
  768. sequence res, digsA
  769. sequence quotient = {}, partial = {SG_PLUS,-1,{}} -- +0
  770. integer signR, expR = -1
  771.  
  772. signR = A[SIGN] * B[SIGN]
  773. if equal({1}, B[DIGITS]) then -- múltiplo de 10
  774. res = {signR, A[EXPONENT] - B[EXPONENT], A[DIGITS]}
  775. else
  776. A[SIGN] = SG_PLUS
  777. B[SIGN] = SG_PLUS
  778.  
  779. A = expand(A)
  780. digsA = A[DIGITS]
  781. for i = 1 to length(digsA) do
  782. partial[DIGITS] &= digsA[i]
  783. partial[EXPONENT] += 1
  784. quotient &= 0
  785. expR += 1
  786. partial = normalize(partial)
  787. while compare(partial, B) != SG_MINUS do
  788. quotient[$] += 1
  789. partial = ba_sub(partial, B)
  790. end while
  791. partial[SIGN] = SG_PLUS -- por si se ha puesto a cero
  792. partial = expand(partial)
  793. end for
  794. res = normalize({ signR, expR, quotient })
  795. end if
  796.  
  797. return ba_floor(res)
  798. end function
  799. --
  800.  
  801.  
  802. --
  803. -- Devuelve un bigatom con el resultado de la división de dos números.
  804. --
  805. -- Admite atoms, bigatoms y representación de números en una cadena
  806. --
  807. export function ba_divide(object A, object B, integer round = 0)
  808.  
  809. if not bigatom(A) then
  810. A = ba_new(A)
  811. end if
  812. if not bigatom(B) then
  813. B = ba_new(B)
  814. end if
  815.  
  816. integer signA = A[SIGN], signB = B[SIGN]
  817. if signB = SG_ZERO or
  818. signB = SG_NOVALUE or
  819. signA = SG_NOVALUE
  820. then
  821. return NO_VALUE
  822. elsif signA = SG_ZERO then
  823. return ZERO
  824. end if
  825.  
  826. sequence res
  827. integer decsB, ndecs
  828. integer expA = A[EXPONENT], expB = B[EXPONENT]
  829. if equal({1}, B[DIGITS]) then
  830. A[EXPONENT] -= expB
  831. A[SIGN] *= signB
  832. res = A
  833. else
  834. ndecs = scale_of(A)
  835. decsB = scale_of(B)
  836. if ndecs < decsB then
  837. ndecs = decsB
  838. end if
  839.  
  840. integer mult = SCALE + 1 -- uno extra para redondeo
  841. if SC_MODE then
  842. if expA > expB then
  843. mult += expA - expB
  844. else
  845. mult += expB - expA
  846. end if
  847. end if
  848. A[EXPONENT] += ndecs + mult
  849. B[EXPONENT] += ndecs
  850.  
  851. res = ba_idivide(A, B)
  852. res[EXPONENT] -= mult
  853. end if
  854.  
  855. if SC_MODE and res[EXPONENT] < 0 then
  856. ndecs = SCALE + 1
  857. else
  858. ndecs = res[EXPONENT] + SCALE + 2
  859. end if
  860. if ndecs > 0 then
  861. if round then
  862. res = round_digits(res, ndecs)
  863. else
  864. res[DIGITS] = remove(res[DIGITS], ndecs, length(res[DIGITS]))
  865. res = normalize(res)
  866. end if
  867. else
  868. res = ZERO
  869. end if
  870.  
  871. return res
  872. end function
  873. --
  874.  
  875.  
  876. -- -------------------------------------------------------------------------------------------
  877.  
  878.  
  879. -- #####################################
  880. -- ### RESTOS, REDONDEOS, VARIOS ###
  881. -- #####################################
  882.  
  883. --
  884. -- Devuelve un bigatom con el resto de la división de dos números.
  885. --
  886. -- Admite atoms, bigatoms o cadenas que representen números
  887. --
  888. export function ba_remainder(object A, object B)
  889.  
  890. if not bigatom(A) then
  891. A = ba_new(A)
  892. end if
  893. if not bigatom(B) then
  894. B = ba_new(B)
  895. end if
  896.  
  897. if A[SIGN] = SG_NOVALUE or
  898. B[SIGN] = SG_NOVALUE or
  899. B[SIGN] = SG_ZERO
  900. then
  901. return NO_VALUE
  902. end if
  903.  
  904. sequence res = ZERO
  905. integer comp = compare(ba_abs(A), ba_abs(B))
  906. if comp > 0 then
  907. res = ba_trunc(ba_divide(A, B))
  908. res = ba_multiply(res, B)
  909. res = ba_sub(A, res)
  910. elsif comp < 0 then
  911. res = A
  912. end if
  913.  
  914. return res
  915. end function
  916. --
  917.  
  918.  
  919. --
  920. -- mi función de redondeo adaptada a bigatom
  921. -- redondea igual lo números negativos que los positivos
  922. -- -0.5 --> -1 en lugar de -0.5 --> 0
  923. --
  924. export function ba_round(object N, atom precision = 1, integer mode = 0)
  925.  
  926. if not bigatom(N) then
  927. N = ba_new(N)
  928. end if
  929.  
  930. if N[SIGN] = SG_NOVALUE then
  931. return NO_VALUE
  932. end if
  933.  
  934. if not precision then
  935. precision = 1
  936. elsif precision < 0 then
  937. precision = -1 / precision
  938. end if
  939.  
  940. sequence res
  941. if mode > 0 then
  942. -- n = ceil(n * precision) / precision
  943. res = ba_ceil(ba_multiply(N, precision))
  944. elsif mode < 0 then
  945. -- n = floor(n * precision) / precision
  946. res = ba_floor(ba_multiply(N, precision))
  947. else -- mode = 0
  948. -- n = sign * floor(sign * a * precision + 0.5) / precision
  949. res = ba_multiply(N, N[SIGN])
  950. res = ba_multiply(res, precision)
  951. res = ba_add(res, {SG_PLUS, -1, {5}}) -- 0.5
  952. res = ba_multiply(ba_floor(res), N[SIGN])
  953. end if
  954. res = ba_divide(res, precision, 1)
  955.  
  956. return res
  957. end function
  958. --
  959.  
  960.  
  961. --
  962. -- devuelve el valor absoluto de un bigatom
  963. --
  964. export function ba_abs(bigatom N)
  965. if N[SIGN] = SG_MINUS then
  966. N[SIGN] = SG_PLUS
  967. end if
  968.  
  969. return N
  970. end function
  971. --
  972.  
  973.  
  974. --
  975. -- devuelve la parte entera de un bigatom
  976. --
  977. export function ba_trunc(bigatom N)
  978. if N[SIGN] = SG_NOVALUE then
  979. return NO_VALUE
  980. elsif N[EXPONENT] < 0 then
  981. return ZERO
  982. end if
  983.  
  984. N[DIGITS] = remove(N[DIGITS], N[EXPONENT] + 2, length(N[DIGITS]))
  985.  
  986. return normalize(N)
  987. end function
  988. --
  989.  
  990.  
  991. --
  992. -- devuelve la parte decimal de un bigatom
  993. --
  994. export function ba_frac(bigatom N)
  995. if N[SIGN] = SG_NOVALUE then
  996. return NO_VALUE
  997. end if
  998.  
  999. if N[EXPONENT] < 0 then
  1000. return N
  1001. end if
  1002. N[DIGITS] = remove(N[DIGITS], 1, N[EXPONENT] + 1)
  1003. N[EXPONENT] = -1
  1004.  
  1005. return normalize(N)
  1006. end function
  1007. --
  1008.  
  1009.  
  1010. --
  1011. -- redondea al entero igual o el inmediato menor
  1012. --
  1013. export function ba_floor(bigatom N)
  1014.  
  1015. if N[SIGN] = SG_NOVALUE then
  1016. return NO_VALUE
  1017. end if
  1018.  
  1019. sequence I = ba_trunc(N)
  1020. if N[SIGN] = SG_MINUS and compare(N, I) then
  1021. I = ba_sub(I, ONE)
  1022. end if
  1023.  
  1024. return I
  1025. end function
  1026. --
  1027.  
  1028.  
  1029. --
  1030. -- redondea al entero igual o el inmediato mayor
  1031. -- (ceil(x) = -floor(-x) )
  1032. export function ba_ceil(bigatom N)
  1033.  
  1034. if N[SIGN] = SG_NOVALUE then
  1035. return NO_VALUE
  1036. end if
  1037.  
  1038. N[SIGN] = -N[SIGN]
  1039. N = ba_floor(N)
  1040. N[SIGN] = -N[SIGN]
  1041.  
  1042. return N
  1043. end function
  1044. --
  1045.  
  1046.  
  1047. -- -------------------------------------------------------------------------------------------
  1048.  
  1049.  
  1050. -- ##################################################
  1051. -- ### FUNCIONES EXPONENCIALES Y LOGARÍTMICAS ###
  1052. -- ##################################################
  1053.  
  1054.  
  1055. --
  1056. -- adaptada de bigfixedmath.e (Lucius L. Hilley III) del Archivo de Euphoria
  1057. -- (más precisa que la interna de euphoria y la que mejor ha ido con bigatom)
  1058. --
  1059. constant LIMIT = 1.1
  1060. --
  1061. override function log(atom x)
  1062.  
  1063. if x <= 0 then -- < 0 no es un real, es complejo (= log(x)+pi*i )
  1064. return eu:log(x) -- = 0 es indefinido (nan)
  1065. end if
  1066.  
  1067. integer inc
  1068. atom res, limit, curr, prev
  1069. if x > LIMIT then
  1070. res = 0
  1071. limit = bigatom:log(LIMIT)
  1072. while x > LIMIT do
  1073. x /= LIMIT
  1074. res += limit
  1075. end while
  1076. res += bigatom:log(x)
  1077.  
  1078. return res
  1079. end if
  1080.  
  1081. prev = x
  1082. x = x - 1
  1083. res = x
  1084. curr = x
  1085. inc = 1
  1086. while res != prev do
  1087. prev = res
  1088. curr *= x
  1089. inc += 1
  1090. res -= curr / inc
  1091. curr *= x
  1092. inc += 1
  1093. res += curr/ inc
  1094. end while
  1095.  
  1096. return res
  1097. end function
  1098. --
  1099.  
  1100. export function logb(atom x, integer base = 10)
  1101. if base > 0 then
  1102. base = -base
  1103. end if
  1104. base = -floor(base)
  1105.  
  1106. return log(x) / log(base)
  1107. end function
  1108. --
  1109.  
  1110.  
  1111. --
  1112. -- cálculo del número de Euler (e) y sus potencias
  1113. -- e = 2.718281828459045235360287471352662497757247093699959574
  1114. -- 9669676277240766303535475945713821785251664274274663919...
  1115. -- adaptada de la librería de bc
  1116. --
  1117. -- override por si se ha incluido math.e
  1118. --
  1119. override function exp(atom x)
  1120.  
  1121. integer neg = 0, mult = 0
  1122. if x < 0 then
  1123. neg = 1
  1124. x = -x
  1125. end if
  1126.  
  1127. while x > 1 do
  1128. mult += 1
  1129. x /= 2
  1130. end while
  1131.  
  1132. integer inc = 2
  1133. atom xpow = x, curr = x
  1134. atom fact = 1, res = 1 + x
  1135. while curr do
  1136. xpow *= x
  1137. fact *= inc
  1138. curr = xpow / fact
  1139. res += curr
  1140. inc += 1
  1141. end while
  1142.  
  1143. while mult do
  1144. res *= res
  1145. mult -= 1
  1146. end while
  1147.  
  1148. if neg then
  1149. res = 1 / res
  1150. end if
  1151.  
  1152. return res
  1153. end function
  1154. --
  1155.  
  1156.  
  1157. --
  1158. -- raíz cuadrada
  1159. --
  1160. override function sqrt(atom x)
  1161. if x < 0 then
  1162. return eu:sqrt(x) -- no es un real, es imaginario (= sqrt(-x)i )
  1163. elsif x = 0 then
  1164. return 0
  1165. elsif x = 1 then
  1166. return 1
  1167. end if
  1168.  
  1169. atom res, res1
  1170. if x < 1 then
  1171. res = 1
  1172. else
  1173. res1 = -floor(-eu:log(x) * 0.5)
  1174. res = power(10, res1)
  1175. end if
  1176.  
  1177. while res != res1 do
  1178. res1 = res
  1179. res = x / res
  1180. res += res1
  1181. res *= 0.5
  1182. end while
  1183.  
  1184. return res
  1185. end function
  1186. --
  1187.  
  1188.  
  1189. -- -------------------------------------------------------------------------------------------
  1190. --
  1191. -- -------------------------------------------------------------------------------------------
  1192.  
  1193.  
  1194.  
  1195. --
  1196. constant BLIMIT = {1,0,{1,1}} -- 1.1
  1197. --
  1198. -- Devuelve un bigatom con el logaritmo natural
  1199. --
  1200. -- Admite atoms, bigatoms y representación de números en una cadena
  1201. --
  1202. -- adaptada de bigfixedmath.e (Lucius L. Hilley III) del archivo de euphoria
  1203. -- (la que mejor ha rendido con bigatoms)
  1204. --
  1205. export function ba_log(object x, integer round = 0)
  1206.  
  1207. if not bigatom(x) then
  1208. x = ba_new(x)
  1209. end if
  1210.  
  1211. if x[SIGN] < SG_PLUS then
  1212. return NO_VALUE
  1213. end if
  1214.  
  1215. sequence sc = scale(SCALE + 4, 0)
  1216.  
  1217. sequence limit, ln_limit
  1218. sequence res, curr, prev, inc
  1219. if compare(ONE, x) = SG_PLUS then
  1220. res = ba_log(ba_divide(ONE, x))
  1221. res[SIGN] = -res[SIGN]
  1222. elsif compare(x, BLIMIT) = SG_PLUS then
  1223. res = ZERO
  1224. ln_limit = ba_log(BLIMIT)
  1225. while compare(x, BLIMIT) = SG_PLUS do
  1226. x = ba_divide(x, BLIMIT)
  1227. res = ba_add(res, ln_limit)
  1228. end while
  1229. res = ba_add(res, ba_log(x))
  1230. else
  1231. -- ln(x) = x - x^2/2 + x^3/3 - x^4/4 + x^5/5 - ...
  1232. prev = x
  1233. x = ba_sub(x, ONE)
  1234. curr = x
  1235. res = x
  1236. inc = {1, 0, {2}} -- 2
  1237. while compare(prev, res) do
  1238. prev = res
  1239. curr = ba_multiply(curr, x)
  1240. res = ba_sub(res, ba_divide(curr, inc))
  1241. inc = ba_add(inc, ONE)
  1242. curr = ba_multiply(curr, x)
  1243. res = ba_add(res, ba_divide(curr, inc))
  1244. inc = ba_add(inc, ONE)
  1245. end while
  1246. end if
  1247.  
  1248. scale(sc)
  1249.  
  1250. if round then
  1251. res = round_digits(res, res[EXPONENT] + 3 + SCALE)
  1252. else
  1253. res[DIGITS] = remove(res[DIGITS],
  1254. res[EXPONENT] + 2 + SCALE,
  1255. length(res[DIGITS]))
  1256. res = normalize(res)
  1257. end if
  1258.  
  1259. return res
  1260. end function
  1261. --
  1262.  
  1263.  
  1264. --
  1265. -- Devuelve un bigatom con la potencia de e (e^x)
  1266. -- e = 2.71828182845904523536028747135266249775724709369995
  1267. -- 95749669676277240766303535475945713821785251664274...
  1268. -- ba_exp(1) = e
  1269. --
  1270. -- Admite atoms, bigatoms y representación de números en una cadena
  1271. --
  1272. -- adaptada de la librería de bc
  1273. --
  1274. export function ba_exp(object x, integer round = 0)
  1275.  
  1276. if not bigatom(x) then
  1277. x = ba_new(x)
  1278. end if
  1279.  
  1280. if equal(x, ONE) then
  1281. return euler(SCALE, 1) -- muchísimo más rápida
  1282. end if
  1283.  
  1284. integer neg = 0, mult = 0
  1285. sequence sc, limit, inc = {1, 0, {2}}
  1286. sequence xpow, curr, res, fact
  1287.  
  1288. if x[SIGN] = SG_MINUS then
  1289. neg = 1
  1290. x[SIGN] = -x[SIGN]
  1291. end if
  1292.  
  1293. sc = scale(SCALE + 2, 0)
  1294.  
  1295. while compare(x, ONE) = SG_PLUS do
  1296. mult += 1
  1297. x = ba_divide(x, {1, 0, {2}})
  1298. end while
  1299.  
  1300. curr = x
  1301. xpow = x
  1302. res = ba_add(x, ONE)
  1303. fact = ONE
  1304. while curr[SIGN] do
  1305. xpow = ba_multiply(xpow, x)
  1306. fact = ba_multiply(fact, inc)
  1307. curr = ba_divide(xpow, fact)
  1308. res = ba_add(res, curr)
  1309. inc = ba_add(inc, ONE)
  1310. end while
  1311.  
  1312. while mult do
  1313. res = ba_multiply(res, res)
  1314. mult -= 1
  1315. end while
  1316. if neg then
  1317. res = ba_divide(ONE, res)
  1318. end if
  1319. scale(sc)
  1320.  
  1321. if round then
  1322. res = round_digits(res, res[EXPONENT] + 2 + SCALE)
  1323. else
  1324. res[DIGITS] = remove(res[DIGITS],
  1325. res[EXPONENT] + 2 + SCALE,
  1326. length(res[DIGITS]))
  1327. res = normalize(res)
  1328. end if
  1329.  
  1330. return res
  1331. end function
  1332. --
  1333.  
  1334.  
  1335. --
  1336. -- Devuelve un bigatom con la potencia de x (x^exp)
  1337. --
  1338. -- Admite atoms, bigatoms y representación de números en una cadena
  1339. --
  1340. export function ba_power(object x, object exponent, integer round = 0)
  1341. sequence res
  1342.  
  1343. if not bigatom(x) then
  1344. if atom(x) and atom(exponent) then
  1345. if floor(exponent) = exponent then
  1346. res = intf_power(ba_new(x), exponent)
  1347. elsif exponent > 0 then
  1348. res = ba_exp(ba_multiply(ba_log(x), exponent), round)
  1349. elsif exponent then
  1350. res = ba_divide(ONE, ba_exp(ba_multiply(ba_log(x), -exponent), round))
  1351. else
  1352. res = ONE
  1353. end if
  1354.  
  1355. return res
  1356. end if
  1357. x = ba_new(x)
  1358. end if
  1359.  
  1360. if atom(exponent) and floor(exponent) = exponent then
  1361. res = intf_power(x, exponent)
  1362.  
  1363. return res
  1364. end if
  1365.  
  1366. if not bigatom(exponent) then
  1367. exponent = ba_new(exponent)
  1368. end if
  1369.  
  1370. if equal(ba_floor(exponent), exponent) then
  1371. res = intf_power(x, bigatom_to_atom(exponent))
  1372. elsif exponent[SIGN] = SG_PLUS then
  1373. res = ba_exp(ba_multiply(ba_log(x), exponent), round)
  1374. elsif exponent[SIGN] = SG_MINUS then
  1375. exponent[SIGN] = -exponent[SIGN]
  1376. res = ba_divide(ONE, ba_exp(ba_multiply(ba_log(x), exponent)), round)
  1377. else
  1378. res = ONE
  1379. end if
  1380.  
  1381. return res
  1382. end function
  1383. --
  1384.  
  1385.  
  1386. --
  1387. -- Devuelve un bigatom con la raíz cuadrada de x
  1388. --
  1389. -- Admite atoms, bigatoms y representación de números en una cadena
  1390. --
  1391. export function ba_sqrt(object x, integer round = 0)
  1392.  
  1393. if not bigatom(x) then
  1394. x = ba_new(x)
  1395. end if
  1396.  
  1397. if x[SIGN] < 0 then
  1398. -- no es un real, es imaginario (= sqrt(-x)*i )
  1399. return NO_VALUE
  1400. elsif x[SIGN] = SG_ZERO then
  1401. return ZERO
  1402. end if
  1403.  
  1404. integer cmp = compare(x, ONE)
  1405. if not compare(x, ONE) then
  1406. return ONE
  1407. end if
  1408.  
  1409. sequence res, res1
  1410. if cmp < 1 then
  1411. -- si 0 < x < 1, inicialmente 1
  1412. res = ONE
  1413. else
  1414. -- si x > 1, inicio en 10^(exp/2) = 10^(exp*0.5)
  1415. res1 = ba_floor(ba_multiply(x[EXPONENT] + 1, {1,-1,{5}}))
  1416. res = ba_power({1,1,{1}}, res1)
  1417. end if
  1418.  
  1419. while compare(res, res1) do
  1420. res1 = res
  1421. res = ba_divide(x, res)
  1422. res = ba_add(res, res1)
  1423. res = ba_multiply(res, {1,-1,{5}}) -- 0.5
  1424. end while
  1425.  
  1426. if round then
  1427. res = round_digits(res, res[EXPONENT] + 2 + SCALE)
  1428. else
  1429. res[DIGITS] = remove(res[DIGITS],
  1430. res[EXPONENT] + 2 + SCALE,
  1431. length(res[DIGITS]))
  1432. res = normalize(res)
  1433. end if
  1434.  
  1435. return res
  1436. end function
  1437. --
  1438.  
  1439.  
  1440. --
  1441. -- Devuelve un bigatom con la raíz n de x (x^(1/n))
  1442. --
  1443. -- Admite atoms, bigatoms y representación de números en una cadena
  1444. --
  1445. export function ba_root(object x, object exponent, integer round = 0)
  1446. sequence res
  1447.  
  1448. sequence sc = scale(SCALE + 1)
  1449. if not bigatom(x) then
  1450. if atom(x) and atom(exponent) then
  1451. if x < 0 or not exponent then
  1452. res = NO_VALUE
  1453. elsif exponent > 0 then
  1454. if exponent = 2 then
  1455. res = ba_sqrt(x) -- muy habitual y mucho más rápida
  1456. else
  1457. res = ba_power(x, 1 / exponent)
  1458. end if
  1459. else
  1460. res = ba_divide(ONE, ba_power(x, 1 / -exponent))
  1461. end if
  1462. scale(sc)
  1463.  
  1464. return ba_multiply(res, 1, round)
  1465. end if
  1466. x = ba_new(x)
  1467. end if
  1468.  
  1469. if not bigatom(exponent) then
  1470. if atom(exponent) and exponent = 2 then
  1471. res = ba_sqrt(x)
  1472. scale(sc)
  1473.  
  1474. return ba_multiply(res, 1, round)
  1475. end if
  1476. exponent = ba_new(exponent)
  1477. end if
  1478.  
  1479. if x[SIGN] != SG_PLUS or
  1480. exponent[SIGN] = SG_NOVALUE or
  1481. not exponent[SIGN]
  1482. then
  1483. res = NO_VALUE
  1484. elsif exponent[SIGN] = SG_PLUS then
  1485. res = ba_power(x, ba_divide(ONE, exponent))
  1486. else
  1487. exponent[SIGN] = -exponent[SIGN]
  1488. res = ba_divide(ONE, ba_power(x, ba_divide(ONE, exponent)))
  1489. end if
  1490. scale(sc)
  1491.  
  1492. return ba_multiply(res, 1, round)
  1493. end function
  1494. --
  1495.  
  1496.  
  1497. --
  1498. -- Devuelve un bigatom con el logaritmo en base b de x
  1499. --
  1500. -- Admite atoms, bigatoms y representación de números en una cadena
  1501. --
  1502. export function ba_logb(object x, object base = 10, integer round = 0)
  1503. if not bigatom(x) then
  1504. x = ba_new(x)
  1505. end if
  1506. if not bigatom(base) then
  1507. base = ba_new(base)
  1508. end if
  1509. base[SIGN] = SG_PLUS
  1510. base = ba_ceil(base)
  1511.  
  1512. return ba_divide(ba_log(x), ba_log(base), round)
  1513. end function
  1514. --
  1515.  
  1516.  
  1517. -- -------------------------------------------------------------------------------------------
  1518.  
  1519.  
  1520. -- ###############################################################
  1521. -- ### FUNCIONES DE CONVERSION Y MANIPULACIÓN DE BIGATOMS ###
  1522. -- ###############################################################
  1523.  
  1524.  
  1525. --
  1526. -- Devuelve una cadena con la representación del número formateado.
  1527. --
  1528. -- sign: si es distinto de cero también muestra el signo en los números positivos.
  1529. -- si es cero el signo solo se muestra en los números negativos.
  1530. --
  1531. -- decs: es el número de decimales a mostrar (con el último decimal redondeado).
  1532. -- Si es negativo se muestra el número con todos sus decimales.
  1533. -- Si no, se rellena de ceros u otro carácter hasta completar la cantidad de
  1534. -- decimales pedida o se recorta y redondea al último decimal.
  1535. --
  1536. -- zsign: poner signo al cero cuando el número es menor que los límites de representación
  1537. -- pero su valor no es cero en la escala actual.
  1538. --
  1539. -- all: indica si deben mostrarse también decimales en todos los números. No se muestran
  1540. -- si es cero. Si es uno le añade el punto decimal y los ceros necesarios hasta
  1541. -- completar el número de decimales y, si es mayor que uno se utiliza el carácter
  1542. -- DFCHAR en lugar de ceros.
  1543. --
  1544. function to_string(sequence N, integer sign = 0, integer decs = -1,
  1545. integer zsign = 0, integer all = 0)
  1546.  
  1547. if N[SIGN] = SG_NOVALUE then
  1548. return "<no_value>"
  1549. end if
  1550.  
  1551. N = expand(N)
  1552.  
  1553. integer sg, exponent
  1554. sequence digits
  1555. {sg, exponent, digits} = N
  1556.  
  1557. -- ajustar al número de decimales solicitado
  1558. integer decsN = length(digits) - exponent - 1
  1559. if decs < 0 then
  1560. decs = decsN
  1561. end if
  1562.  
  1563. integer last = exponent + 1 + decs
  1564. if decs < decsN then
  1565. if digits[last + 1] >= 5 then
  1566. -- redondea el último decimal
  1567. digits = digits_add(digits[1..last], {1})
  1568. exponent += digits[1]
  1569. digits = digits[2]
  1570. else
  1571. digits = digits[1..last]
  1572. end if
  1573. elsif all or decsN then
  1574. if all = 1 then
  1575. digits &= repeat(0, decs - decsN)
  1576. elsif all then
  1577. digits &= repeat(DFCHAR - '0', decs - decsN)
  1578. end if
  1579. end if
  1580.  
  1581. if compare(digits, repeat(0, length(digits) - exponent)) then
  1582. zsign = 0
  1583. end if
  1584.  
  1585. digits += '0'
  1586.  
  1587. -- poner punto decimal
  1588. integer dp = exponent + 2
  1589. if dp <= length(digits) then
  1590. digits = insert(digits, '.', dp)
  1591. end if
  1592.  
  1593. -- poner signo
  1594. if sg = SG_MINUS then
  1595. digits = prepend(digits, SMINUS)
  1596. elsif sg and (sign or zsign) then
  1597. digits = prepend(digits, SPLUS)
  1598. else -- if sign then
  1599. digits = prepend(digits, SZERO)
  1600. end if
  1601.  
  1602. return digits
  1603. end function
  1604. --
  1605.  
  1606.  
  1607. --
  1608. -- Devuelve un atom con el valor de un bigatom
  1609. --
  1610. export function bigatom_to_atom(bigatom N)
  1611. atom val = 0
  1612. integer sg = N[SIGN]
  1613. sequence digits = N[DIGITS]
  1614. if length(digits) then
  1615. atom div = 10
  1616. val = digits[1]
  1617. for i = 2 to length(digits) do
  1618. val += digits[i] / div
  1619. div *= 10
  1620. end for
  1621. val *= sg * power(10, N[EXPONENT])
  1622. end if
  1623.  
  1624. return val
  1625. end function
  1626. --
  1627.  
  1628.  
  1629. --
  1630. -- Devuelve un bigatom con el valor de un entero (integer)
  1631. --
  1632. function int_to_bigatom(integer i)
  1633. integer sign = SG_ZERO
  1634. if i > 0 then
  1635. sign = SG_PLUS
  1636. else
  1637. sign = SG_MINUS
  1638. end if
  1639. sequence s = sprintf("%+d", i) - '0'
  1640. s = remove(s, 1)
  1641.  
  1642. return normalize({sign, length(s) - 1, s})
  1643. end function
  1644. --
  1645.  
  1646.  
  1647. --
  1648. -- Devuelve un atom con el valor entero de una cadena que contiene la
  1649. -- representación de un número.
  1650. --
  1651. -- La conversión se detiene al encontrar el primer carácter no válido.
  1652. -- Permite el uso de espacios y subrayados como separadores de grupos.
  1653. -- Si la cadena contiene un número con decimales devuelve el valor de
  1654. -- su parte entera, el punto o la coma detienen la conversion.
  1655. --
  1656. export function int_value(sequence str)
  1657. if not length(str) then
  1658. return 0
  1659. end if
  1660.  
  1661. integer digit
  1662. integer sign = (str[1] = SPLUS) - (str[1] = SMINUS)
  1663. if sign then
  1664. str = remove(str, 1)
  1665. else
  1666. sign = 1
  1667. end if
  1668.  
  1669. atom ival = 0
  1670. for i = 1 to length(str) do
  1671. if not integer(str[i]) then
  1672. exit
  1673. end if
  1674. digit = str[i]
  1675. if digit >= '0' and digit <= '9' then
  1676. ival = ival * 10 + (digit - '0')
  1677. elsif digit != UNDERLINE and digit != SPACE then
  1678. exit
  1679. end if
  1680. end for
  1681.  
  1682. return sign * ival
  1683. end function
  1684. --
  1685.  
  1686.  
  1687. --
  1688. -- Normaliza un bigatom.
  1689. -- Reduce un bigatom a su forma más corta eliminando
  1690. -- los ceros superfluos y ajusta el exponente.
  1691. --
  1692. export function normalize(sequence N)
  1693. if N[SIGN] < SG_MINUS or N[SIGN] > SG_PLUS then
  1694. return NO_VALUE
  1695. end if
  1696.  
  1697. sequence mantissa = N[DIGITS]
  1698. integer first = 1, last = length(mantissa)
  1699. while last and mantissa[last] = 0 do
  1700. last -= 1
  1701. end while
  1702. while first <= last and mantissa[first] = 0 do
  1703. first += 1
  1704. end while
  1705.  
  1706. if first > last or not N[SIGN] then
  1707. N = ZERO
  1708. else
  1709. N[DIGITS] = mantissa[first..last]
  1710. N[EXPONENT] -= first - 1
  1711. end if
  1712.  
  1713. return N
  1714. end function
  1715. --
  1716.  
  1717.  
  1718. --
  1719. -- expande un bigatom con todos sus dígitos
  1720. --
  1721. function expand(sequence N)
  1722. sequence digits = N[DIGITS]
  1723. integer exponent = N[EXPONENT]
  1724. integer len = length(digits) - 1
  1725.  
  1726. if exponent < 0 then
  1727. digits = repeat(0, -exponent) & digits
  1728. N[EXPONENT] = 0
  1729. elsif exponent > len then
  1730. digits &= repeat(0, exponent - len)
  1731. end if
  1732. N[DIGITS] = digits
  1733.  
  1734. return N
  1735. end function
  1736. --
  1737.  
  1738.  
  1739. --
  1740. -- devuelve ambos números con las sequences de dígitos alineadas e igualadas
  1741. -- en tamaño añadiendo los ceros necesarios tanto a derecha como a izquierda
  1742. -- de los dígitos de ambos números.
  1743. -- Igualando los exponentes y con el mismo número de dígitos en ambas mantisas.
  1744. --
  1745. function align(sequence A, sequence B)
  1746. integer expA, expB, offset
  1747. sequence digsA, digsB
  1748.  
  1749. {?, expA, digsA} = A
  1750. {?, expB, digsB} = B
  1751.  
  1752. -- poner ceros a la izquierda
  1753. offset = expA - expB
  1754. if offset > 0 then
  1755. digsB = repeat(0, offset) & digsB
  1756. expB += offset
  1757. else
  1758. digsA = repeat(0, -offset) & digsA
  1759. expA -= offset
  1760. end if
  1761.  
  1762. -- poner ceros a la derecha
  1763. offset = length(digsA) - length(digsB)
  1764. if offset > 0 then
  1765. digsB &= repeat(0, offset)
  1766. else
  1767. digsA &= repeat(0, -offset)
  1768. end if
  1769.  
  1770. -- elimina ceros sobrantes
  1771. integer last = length(digsA)
  1772. while last and digsA[last] = 0 and digsB[last] = 0 do
  1773. last -= 1
  1774. end while
  1775. A[DIGITS] = digsA[1..last]
  1776. B[DIGITS] = digsB[1..last]
  1777. A[EXPONENT] = expA
  1778. B[EXPONENT] = expB
  1779.  
  1780. return { A, B }
  1781. end function
  1782. --
  1783.  
  1784.  
  1785. --
  1786. -- suma dos sequences de dígitos
  1787. -- devuelve una sequence de dos elementos: { acarreo, resultado }
  1788. -- si acarreo no es cero indica que se ha producido un exceso en la suma
  1789. -- y por ello la longitud del resultado se ha incrementado en 1.
  1790. --
  1791. function digits_add(sequence a, sequence b)
  1792. integer len = length(a), lenb = length(b)
  1793. if len < lenb then
  1794. a = repeat(0, lenb - len) & a
  1795. len = lenb
  1796. elsif lenb < len then
  1797. b = repeat(0, len - lenb) & b
  1798. end if
  1799.  
  1800. sequence result = a + b
  1801.  
  1802. integer carry = 0, digit
  1803. for i = len to 1 by -1 do
  1804. digit = result[i] + carry
  1805. carry = digit > 9
  1806. if carry then
  1807. digit -= 10
  1808. end if
  1809. result[i] = digit
  1810. end for
  1811. if carry then
  1812. result = prepend(result, carry)
  1813. end if
  1814.  
  1815. return { carry, result }
  1816. end function
  1817. --
  1818.  
  1819.  
  1820. --
  1821. -- resta dos sequences de dígitos
  1822. -- devuelve una sequence de dos elementos: { negativo, resultado }
  1823. -- si negativo no es cero indica que el resultado es negativo.
  1824. --
  1825. function digits_sub(sequence a, sequence b)
  1826.  
  1827. integer len = length(a), lenb = length(b)
  1828. if len < lenb then
  1829. a = repeat(0, lenb - len) & a
  1830. len = lenb
  1831. elsif lenb < len then
  1832. b = repeat(0, len - lenb) & b
  1833. end if
  1834.  
  1835. sequence result = a - b
  1836.  
  1837. integer digit, neg = 0
  1838. for i = len to 1 by -1 do
  1839. digit = result[i] - neg
  1840. neg = digit < 0
  1841. if neg then
  1842. digit += 10
  1843. end if
  1844. result[i] = digit
  1845. end for
  1846. -- si es negativo está en complemento a 10
  1847. if neg then
  1848. result = 9 - result -- complemento a 9
  1849. result = digits_add(result, {1}) -- más 1
  1850. result = result[2]
  1851. end if
  1852.  
  1853. return { neg, result }
  1854. end function
  1855. --
  1856.  
  1857.  
  1858. --
  1859. -- multiplica dos sequences de dígitos
  1860. -- devuelve una sequence de dos elementos: { acarreo, resultado }
  1861. -- si acarreo no es cero indica que se ha producido un exceso en la suma
  1862. -- y la longitud del resultado se ha incrementado en 1.
  1863. --
  1864. function digits_multiply(sequence a, sequence b)
  1865. integer lena = length(a), lenb = length(b)
  1866. if lena < lenb then
  1867. {a, lena, b, lenb} = {b, lenb, a, lena}
  1868. end if
  1869.  
  1870. sequence partial, result = {}
  1871. integer digit, carry
  1872. for i = lenb to 1 by -1 do
  1873. carry = 0
  1874. partial = a * b[i] & repeat(0, lenb - i)
  1875. for j = lena to 1 by -1 do
  1876. digit = partial[j] + carry
  1877. carry = 0
  1878. if digit > 9 then
  1879. carry = floor(digit / 10)
  1880. digit = remainder(digit, 10)
  1881. end if
  1882. partial[j] = digit
  1883. end for
  1884. if carry then
  1885. partial = prepend(partial, carry)
  1886. end if
  1887. result = digits_add(result, partial)
  1888. carry += result[1]
  1889. result = result[2]
  1890. end for
  1891.  
  1892. return { carry, result }
  1893. end function
  1894. --
  1895.  
  1896.  
  1897. --
  1898. -- redondea el dígito dignum de la mantisa de un bigatom
  1899. -- devuelve un bigatom con el número redondeado con un digito menos.
  1900. --
  1901. function round_digits(sequence N, integer dignum)
  1902. sequence res = N[DIGITS]
  1903.  
  1904. if dignum < 1 or dignum > length(res) then
  1905. return N
  1906. end if
  1907.  
  1908. res = digits_add(res[1..dignum], {5})
  1909. N[EXPONENT] += res[1]
  1910. N[DIGITS] = res[2][1..$-1]
  1911.  
  1912. return normalize(N)
  1913. end function
  1914. --
  1915.  
  1916.  
  1917. --
  1918. -- eleva un bigatom a una potencia entera (uno a uno)
  1919. --
  1920. function ipower(sequence A, integer exponent)
  1921. sequence res
  1922. if exponent = 0 then
  1923. return ONE
  1924. else
  1925. res = A
  1926. for i = 2 to exponent do
  1927. res = ba_multiply(A, res)
  1928. end for
  1929. end if
  1930.  
  1931. return res
  1932. end function
  1933. --
  1934.  
  1935.  
  1936. --
  1937. -- eleva un bigatom a una potencia entera (descompone en factores primos)
  1938. -- seguro que hay mejores modos de hacerlo, pero al menos da el resultado
  1939. -- exacto con exponentes enteros
  1940. --
  1941. function intf_power(sequence A, integer exponent)
  1942. if exponent = 0 then
  1943. return ONE -- por conveniencia 0^0 = 1 (el término neutro de la multiplicación)
  1944. end if
  1945.  
  1946. sequence res
  1947. if A[SIGN] = SG_ZERO then
  1948. if exponent < 0 then
  1949. res = NO_VALUE
  1950. else
  1951. res = ZERO
  1952. end if
  1953. elsif exponent < 0 then
  1954. res = ba_divide(ONE, intf_power(A, -exponent))
  1955. if res[SIGN] then
  1956. res[SIGN] = A[SIGN]
  1957. end if
  1958. elsif equal({1}, A[DIGITS]) then
  1959. res = A
  1960. res[EXPONENT] *= exponent
  1961. else
  1962. sequence factors = get_factors(exponent)
  1963. res = A
  1964. for i = 1 to length(factors) do
  1965. res = ipower(res, factors[i])
  1966. end for
  1967. end if
  1968.  
  1969. return res
  1970. end function
  1971. --
  1972.  
  1973.  
  1974. --
  1975. -- descompone un entero en sus factores primos
  1976. --
  1977. function get_factors(integer n)
  1978. sequence flist = {}
  1979.  
  1980. while not remainder(n, 2) do
  1981. flist &= 2
  1982. n /= 2
  1983. end while
  1984.  
  1985. integer factor = 3
  1986. while n >= factor do
  1987. while remainder(n, factor) do
  1988. factor += 2
  1989. end while
  1990. flist &= factor
  1991. n /= factor
  1992. end while
  1993. if not length(flist) then
  1994. flist = {n}
  1995. end if
  1996.  
  1997. return flist
  1998. end function
  1999. --
  2000.  
  2001.  
  2002. --
  2003. -- Calcula el número de Euler (e) con precisión arbitraria
  2004. -- comprobado hasta un millón de decimales, donde miré por internet un diff y solo
  2005. -- difería el último decimal, aunque tarda un poquillo... jejeje echará humo...
  2006. -- según la máquina claro.
  2007. --
  2008. -- decs: número de decimales de e (>=0)
  2009. -- output: si es cero devuelve una cadena, si es
  2010. -- distinto de cero, devuelve un bigatom
  2011. --
  2012. -- Algoritmo original escrito en Algol por Serge Batalov
  2013. -- Reescrito en Modula-2 y modificado por Eugene Nalimov y Pavel Zemtsov
  2014. -- Adaptado a Euphoria por Carlos J. Gómez Andreu (cargoan)
  2015. --
  2016. constant N = 4, -- grupo
  2017. P = 10000 -- base (10^N)
  2018. --
  2019. export function euler(integer decs, integer output = 0)
  2020. if decs < 0 then
  2021. decs = 0
  2022. end if
  2023. integer d = decs
  2024. if remainder(decs, N) then -- al múltiplo de N decimales
  2025. d += N - remainder(decs, N)
  2026. end if
  2027.  
  2028. atom size = floor(d / N) + 1
  2029. sequence x = repeat(0, size)
  2030. sequence y = repeat(0, size)
  2031. sequence res = {}
  2032.  
  2033. if d > 0 then
  2034. -- ------------------------------------------------------------------
  2035. -- de esto ni idea, adaptado literalmente de un ejemplo de XDS,
  2036. -- compilador de Modula y Oberon para OS/2
  2037. -- ------------------------------------------------------------------
  2038. integer e
  2039. atom k,l,c
  2040. e = size
  2041. y[1] = P
  2042. l = 0
  2043. c = 1
  2044. for i = 1 to e do
  2045. while 1 do
  2046. c += 1
  2047. for j = i to e do
  2048. l = y[j] + l * P
  2049. y[j] = floor(l / c)
  2050. x[j] += y[j]
  2051. l -= c * y[j]
  2052. end for
  2053. if y[i] < c then
  2054. exit
  2055. end if
  2056. l = 0
  2057. end while
  2058. l = y[i]
  2059. end for
  2060.  
  2061. l = 0
  2062. for i = e to 1 by -1 do
  2063. k = x[i] + l
  2064. l = floor(k / P)
  2065. x[i] = k - l * P
  2066. end for
  2067. -- ------------------------------------------------------------------
  2068. -- lo que sé es que aquí x es un array de enteros con los decimales
  2069. -- en base 10^N, que son N dígitos en base 10 por cada elemento
  2070. -- ------------------------------------------------------------------
  2071. sequence s
  2072. integer bdigit
  2073. for i = 1 to e do
  2074. s = repeat(0, N)
  2075. bdigit = x[i]
  2076. size = N
  2077. while size do
  2078. s[size] = remainder(bdigit, 10)
  2079. bdigit = floor(bdigit / 10)
  2080. size -= 1
  2081. end while
  2082. res &= s
  2083. end for
  2084. end if
  2085.  
  2086. if output then
  2087. res = {1, 0, 2 & res[1..decs]}
  2088. elsif decs then
  2089. res = "2." & res[1..decs] + '0'
  2090. else
  2091. res = "2"
  2092. end if
  2093.  
  2094. return res
  2095. end function
  2096. --
  2097.  
  2098. -- -------------------------------------------------------------------------------------------
  2099. -- end bigatom.e
  2100. -- -------------------------------------------------------------------------------------------
  2101.  
  2102. ifdef PRUEBA then
  2103. puts(1, "\nSabías que...\n\n")
  2104. integer n = 2, decs = 100
  2105. scale(decs)
  2106. bigatom ba = ba_sqrt(n)
  2107. printf(1, "La raíz cuadrada de %d con %d decimales es:\n\t%s\n\n",
  2108. { n, decs, ba_sprintf("%.100aB", ba) })
  2109. ba = ba_root(n, 3)
  2110. ba_printf(1, "Y que su raíz cúbica es:\n\t%.100aB\n\n", ba)
  2111. ba = ba_log(n)
  2112. ba_printf(1, "Su logaritmo natural es:\n\t%.100aB\n\n", ba)
  2113. ba = ba_logb(n, 10)
  2114. ba_printf(1, "Y su logaritmo decimal es:\n\t%.100aB\n\n", ba)
  2115. decs = 843
  2116. scale(decs)
  2117. ba = ba_exp("1")
  2118. printf(1, "Y que 'e' con %d decimales es:\n\t%s\n", { decs, ba_sprint(ba) })
  2119. end ifdef
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement