1

EDIT: Issue was floating point math (see here for info: http://floating-point-gui.de/). Changed the formula from:

(votes_yes + votes_no) * .55 

to:

(votes_yes + votes_no) * (55/100)

Django 1.3.7, python 2.7

In my model I'm performing some simple math so that a results field is auto populated upon submission via the admin interface. My problem is that this is not working correctly and was hoping if someone could explain why this might be.

How it should work: If there are 55% or greater yes votes then the result should post as Approved, if not then Failed. The issue is that the result is not correct for, apparently, 2 digit numbers.

eg: If I enter 550 votes_yes and 450 votes_no, the result posts correctly as 'Approved' as you would expect. However, if I enter 55 votes yes and 45 votes no, the result is posted as 'Failed' even though the result of the formula (votes_yes + votes_no) * .55 equals exactly 55 and the result should be Approved.

It appears that If I use 3 digits numbers the results post fine but two digit numbers MUST be greater 55%, rather than greater than or equal to. eg: 56 votes yes and 45 votes works fine. Any help as to why this is happening would be greatly appreciated.

Here an edited version of my model:

MAJORITY_REQUIREMENT = (
...
    ('2', '55%'),
...
)

POSSIBLE_RESULTS = (
    ('1', 'Approved'),
    ('2', 'Failed'),
)

class Measures(models.Model):
    votes_yes = models.IntegerField(blank=False)
    votes_no = models.IntegerField(blank=False)
    result = models.CharField(editable=False, max_length=30, choices=POSSIBLE_RESULTS)
    required_majority = models.CharField(max_length=1, blank=False, choices=MAJORITY_REQUIREMENT, default="1"

# do the math to get the result
    def save(self):
 ...
        if self.required_majority == '2':
            if self.votes_yes >= (self.votes_yes + self.votes_no) * .55:
                self.result = '1'
            else:
                self.result = '2'
...


    def __unicode__(self):
        return self.measure_name
Fish
  • 215
  • 1
  • 9
  • Floating point math, including `100 * 0.55`, is inexact. On my implementation `100 * 0.55` evaluates to `55.000000000000007`. You can either define a reasonable delta, use the `decimal` built in library and sacrifice performance for exactness, or rework to use just integers - (x * 55 / 100) will keep everything in integer math, following the usual Python truncation semantics. – Peter DeGlopper Dec 07 '15 at 17:40
  • Thank you very much for this explanation. I have everything working fine now. – Fish Dec 07 '15 at 18:55

1 Answers1

1

This is due to floating point math. Contrary to what you might expect, doing (45+55)*.55 actually equals 55.00000000000001. What you should instead do with your formula is:

if self.votes_yes >= math.floor((self.votes_yes + self.votes_no) * .55):
coffee-converter
  • 967
  • 4
  • 13