jacknpoe

biblioteca fixed point

Feb 18th, 2026 (edited)
250
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.64 KB | Software | 0 0
  1. """
  2. Biblioteca de testes de conceito de algoritmos de funções úteis para matemática financeira em linguagens que só tenham inteiros.
  3. O fato de ser em Python é para testes dos resultados sem a dificuldade de ser implementada em uma linguagem real.
  4. A solução que é o "domínio do problema" resolve cálculos entre juros e acréscimos, normalmente 0%-10% de juros até 120 parcelas.
  5. Funções que trabalham com logaritmos e exponenciação de fixed-points só são garantidamente precisas dentro desse domínio.
  6. Não se tentou competir com bibliotecas matemáticas prontas, que podem fazer os mesmos cálculos em domínios mais amplos,
  7. ela somente demonstra que, mesmo sem suporte a ponto flutuante (ou fixo) em uma linguagem, ainda se pode implementar matemática
  8. de forma portável, nesse caso, usando séries de Taylor que são precisas especificamente para um problema de matemática financeira.
  9. """
  10.  
  11. # variáveis gerais para fixed-point com 35 dígitos, com escala computada,
  12. # totais de iterações para lnfp() e expfp(), número UM e INFINITO (para legibilidade)
  13. # TOTLN e TOTEXP são superdimensionados para garantir convergência no domínio do problema
  14. DIGITOS = 35
  15. ESCALA = 10 ** DIGITOS
  16. TOTLN = 2 * DIGITOS
  17. TOTEXP = 3 * DIGITOS
  18. UM = ESCALA
  19. INFINITO = ESCALA * ESCALA # aqui deve ser definido um número fora do domínio do problema, por ser impossível na prática
  20.                            # ele é retornado por divfp quando dá divisão por zero, para ser tratado
  21.  
  22. # soma e subtração não mudam escala; usar + e - direto é mais claro; mas nada impede usar para manter o estilo
  23. #
  24. # def addfp(a, b):
  25. #     """operação + de dois fixed-points"""
  26. #     return a + b
  27. #
  28. # def subfp(a, b):
  29. #     """operação - de dois fixed-points"""
  30. #     return a - b
  31.  
  32. def mulfp(a, b):
  33.     """operação * de dois fixed-points"""
  34.     if a * b < 0:
  35.         return (a * b - ESCALA // 2) // ESCALA
  36.     else:
  37.         return (a * b + ESCALA // 2) // ESCALA
  38.  
  39. def divfp(a, b):
  40.     """operação / de dois fixed-points"""
  41.     if b == 0:
  42.         return INFINITO  # divisão por zero retorna valor fora do domínio do problema (ou não trate aqui, se preferir)
  43.     if (a < 0) ^ (b < 0):
  44.         return (a * ESCALA - b // 2) // b
  45.     else:
  46.         return (a * ESCALA + b // 2) // b
  47.  
  48. def inttofp(x):
  49.     """torna um integer em fixed-point com DIGITOS de dígitos (usando ESCALA que já está computada)"""
  50.     return x * ESCALA
  51.  
  52. def lnfp(x):
  53.     """logaritmo natural de um fixed-point; o domínio do problema dessa função é x entre 1.0 e 1.1 (para matemática financeira)"""
  54.     termo = divfp(x - UM, x + UM)
  55.     yy = mulfp(termo, termo)
  56.     soma = 0
  57.  
  58.     for indice in range(TOTLN):
  59.         soma = soma + divfp(termo, inttofp(2 * (indice + 1) - 1))
  60.         termo = mulfp(termo, yy)
  61.  
  62.     return 2 * soma
  63.  
  64. def expfp(x):
  65.     """número de Euler elevado a um fixed-point; o domínio do problema dessa função é x entre 0.0 e 6.0 (para matemática financeira)"""
  66.     termo = UM
  67.     soma = UM
  68.  
  69.     for indice in range(TOTEXP):
  70.         termo = mulfp(termo, divfp(x, inttofp(indice + 1)))
  71.         soma = soma + termo
  72.    
  73.     return soma
  74.  
  75. def powfp(base, expoente):
  76.     """base fixed-point elevada a expoente a fixed-points, essa função tem a precisão de acordo com lnfp() e expfp()
  77.       o domínio do problema dessa função é base entre 1.0 e 1.1 e expoente entre 0 e 120"""
  78.     return expfp(mulfp(expoente, lnfp(base)))
  79.  
  80. def powintfprec(base, expoente):
  81.     """base fixed-point elevada a expoente integer, recursiva, para máxima precisão, expoente pode ser negativo"""
  82.     if expoente < 0:
  83.         return powintfprec(divfp(UM, base), -expoente)
  84.     if expoente == 0:
  85.         return UM
  86.     if expoente % 2 == 0:
  87.         return powintfprec(mulfp(base, base), expoente // 2)
  88.     return mulfp(base, powintfprec(mulfp(base, base), (expoente - 1) // 2))
  89.  
  90. def powintfpfor(base, expoente):
  91.     """base fixed-point elevada a expoente integer, iterativa, para máxima precisão, expoente pode ser negativo"""
  92.     if expoente < 0:
  93.         base = divfp(UM, base)
  94.         expoente = -expoente
  95.     if expoente == 0:
  96.         return UM
  97.     produto = UM
  98.     for indice in range(expoente):
  99.         produto = mulfp(produto, base)
  100.     return produto
  101.  
  102. def powintrec(base, expoente):
  103.     """base integer elevada a expoente integer, recursiva; o domínio da função é fazer 10 ** DIGITOS em linguagens sem **; não aceita expoente negativo"""
  104.     if expoente < 0:
  105.         return 0
  106.     if expoente == 0:
  107.         return 1
  108.     if expoente % 2 == 0:
  109.         return powintrec(base * base, expoente // 2)
  110.     return base * powintrec(base * base, (expoente - 1) // 2)
  111.  
  112. def powintfor(base, expoente):
  113.     """base integer elevada a expoente integer, iterativa; o domínio da função é fazer 10 ** DIGITOS em linguagens sem **; não aceita expoente negativo"""
  114.     if expoente < 0:
  115.         return 0
  116.     if expoente == 0:
  117.         return 1
  118.     produto = 1
  119.     for indice in range(expoente):
  120.         produto = produto * base
  121.     return produto
  122.  
  123. def strfp(x):
  124.     """função para converter o número fixed-poin em string com ponto decimal"""
  125.     sign = "-" if x < 0 else ""
  126.     x = abs(x)
  127.  
  128.     inteiro = x // ESCALA
  129.     frac = x % ESCALA
  130.  
  131.     frac_str = str(frac).rjust(DIGITOS, "0")
  132.  
  133.     # remove zeros à direita (opcional, mas prático)
  134.     frac_str = frac_str.rstrip("0")
  135.  
  136.     if frac_str == "":
  137.         return f"{sign}{inteiro}"
  138.     else:
  139.         return f"{sign}{inteiro}.{frac_str}"
  140.  
  141. ################################################## TESTES ##################################################
  142.  
  143. num1 = inttofp(2)
  144. num2 = inttofp(3)
  145.  
  146. num3 = divfp(num1, num2)
  147. print("div = " + strfp(num3))
  148.  
  149. num3 = mulfp(num1, num2)
  150. print("mul = " + strfp(num3))
  151.  
  152. print("ln = " + strfp(lnfp(num1)))
  153. print("exp = " + strfp(expfp(num1)))
  154.  
  155. base = inttofp(103) // 100  # número 1.03
  156. expoente = inttofp(5) // 10  # número 0.5
  157.  
  158. print("pow = " + strfp(powfp(base, expoente)))
  159.  
  160. minDiferenca = inttofp(1) // 10  # número 0.1
  161. precisao = 15
  162.  
  163. print("powintfprec = " + strfp(powintfprec(minDiferenca, precisao)))
  164. print("powintfpfor = " + strfp(powintfpfor(minDiferenca, precisao)))
  165.  
  166. print("powintrec = " + str(powintrec(10, DIGITOS)))
  167. print("powintfor = " + str(powintfor(10, DIGITOS)))
  168.  
  169. """  RETORNOS DOS TESTES PARA VALIDAÇÃO
  170. div = 0.66666666666666666666666666666666667
  171. mul = 6
  172. ln = 0.69314718055994530941723212145817658
  173. exp = 7.38905609893065022723042746057500784
  174. pow = 1.01488915650922194686485201189358745
  175. powintfprec = 0.000000000000001
  176. powintfpfor = 0.000000000000001
  177. powintrec = 100000000000000000000000000000000000
  178. powintfor = 100000000000000000000000000000000000
  179. """
Add Comment
Please, Sign In to add comment