Guest User

Untitled

a guest
Nov 23rd, 2011
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.17 KB | None | 0 0
  1. #############################################################################
  2. # Anti "float" argument generator.                                          #
  3. #                                                                           #
  4. # The goal of this script is to find a use case where                       #
  5. # using float will produce a different result then using                    #
  6. # decimal for calculation.                                                  #
  7. #                                                                           #
  8. # The reason for the difference is that, while float has                    #
  9. # a pretty large precision (see EPSILON) more than enough                   #
  10. # to handle day-to-day business trasactions, the lost precision             #
  11. # will show eventually when aggregating a not so large data set.            #
  12. # Especially if you apply small percentages to them (like                   #
  13. # interests or taxes).                                                      #
  14. #                                                                           #
  15. # The scenario simulated by this is script is:                              #
  16. #    * A company has an initial balance on an interest-bearing              #
  17. #      account.                                                             #
  18. #    * The account pays a daily interest based on an essentialy             #
  19. #      random market rate.                                                  #
  20. #    * This is simulated a few times and eventually an error should pop.    #
  21. #                                                                           #
  22. # Author: Cloves Almeida (cjalmeida_at_gmail_dot_com)                       #
  23. # Copyright: None. Use at will.                                             #
  24. #############################################################################
  25.  
  26. from decimal import *
  27. import sys
  28.  
  29.  
  30. INITIAL_BALANCE = 116250.00
  31. DAYS = 3650
  32. TABLE_FILE = '/tmp/fdtest.txt'
  33. EPSILON = pow(2,-30)
  34.  
  35. fout = open(TABLE_FILE,'w')
  36. prec = Decimal('.01')
  37.  
  38. def roundf(f):
  39.     return round(f + cmp(f,0)*EPSILON,2)
  40.  
  41. def write_table(tbl):
  42.     for d, s,r,e in tbl:
  43.         write("%s\t%.2f\t%.6f\t%.2f" % (d,s,r,e))
  44.  
  45. def find_error(tblf,tbld):
  46.     for day in xrange(DAYS):
  47.         f = "%.2f" % (tblf[day][3])
  48.         d = str(tbld[day][3])
  49.         if not f == d:
  50.             return day
  51.  
  52. def write(msg):
  53.     fout.write(msg+'\n')
  54.                    
  55. def float_decimal_test():
  56.     import random
  57.  
  58.     # generate daily interest rates
  59.     rates = []
  60.     for i in xrange(DAYS):
  61.         rates.append(round(random.random() * 0.001,6))
  62.  
  63.     # store statement lines
  64.     float_lines = []
  65.     dec_lines = []
  66.    
  67.    
  68.     ### iterate calculating daily interest using floats ###
  69.     balance = INITIAL_BALANCE
  70.     for i in xrange(DAYS):
  71.         start_balance = balance
  72.         rate = rates[i]
  73.         interest = roundf(balance*rate)
  74.         balance = roundf(balance + interest)
  75.         float_lines.append((i, start_balance, rates[i], balance))
  76.  
  77.     b1 = "%.2f" % balance
  78.  
  79.  
  80.     ### iterate calculating daily interest using decimals ###
  81.     balance = Decimal(str(INITIAL_BALANCE)).quantize(prec,rounding=ROUND_HALF_UP)
  82.     for i in xrange(DAYS):
  83.         start_balance = balance
  84.         rate = Decimal(str(rates[i]))
  85.         interest = (balance * rate).quantize(prec,rounding=ROUND_HALF_UP)
  86.         balance += interest
  87.         dec_lines.append((i, start_balance, rate, balance))
  88.  
  89.     b2 = str(balance)
  90.    
  91.     if not b1 == b2:
  92.         write("Float table:")
  93.         write_table(float_lines)
  94.         write("---")
  95.         write("Decimal table:")
  96.         write_table(dec_lines)
  97.        
  98.         print "There you got a use case for using decimal instead of float!"
  99.         day = find_error(float_lines, dec_lines)
  100.         print "Try looking at day %s in file %s" % (day,TABLE_FILE)
  101.  
  102.         raise Exception("bfloat: %s, bdec: %s" % (b1, b2))
  103.        
  104.  
  105. for x in xrange(1000):
  106.     try:
  107.         float_decimal_test()
  108.     except Exception as e:
  109.         print 'Error found in iteration %s: %s' % (x, e.message)
  110.         fout.close()
  111.         sys.exit(1)
  112.  
  113. fout.close()
  114. print 'No error found.'
  115.  
Advertisement
Add Comment
Please, Sign In to add comment