返回浮点值的Python方法为相同的原始数据返回不同的值

返回浮点值的Python方法为相同的原始数据返回不同的值,python,django,floating-point,Python,Django,Floating Point,另一个Python浮点问题。我正在创建一个应用程序来帮助我们的培训部门。这个应用程序的一部分是处理类评估。评估包括一类设备、一份书面测试分数、一份操作测试分数和一份操作测试时间。这将是一个漫长的过程 有一个计算分数的公式: score = written_test + operational - best_decimal_time + decimal_time percentage = score / best score 现在,该界面允许用户输入测试分数以及道路测试的分钟和秒数。理论上,最佳

另一个Python浮点问题。我正在创建一个应用程序来帮助我们的培训部门。这个应用程序的一部分是处理类评估。评估包括一类设备、一份书面测试分数、一份操作测试分数和一份操作测试时间。这将是一个漫长的过程

有一个计算分数的公式:

score = written_test + operational - best_decimal_time + decimal_time
percentage = score / best score
现在,该界面允许用户输入测试分数以及道路测试的分钟和秒数。理论上,最佳时间的分数为:

written_test + operational
因为十进制的时间会相互抵消

请注意,
笔试
评估

使用Django,评估的模型定义为:

class Evaluation(models.Model):
    student = models.ForeignKey(StudentRegistration)
    machine_class = models.ForeignKey(MachineClass)
    operational = models.IntegerField()
    minutes = models.IntegerField(null=True, blank=True, default=0)
    seconds = models.IntegerField(null=True, blank=True, default=0)
    raw_time = models.CharField(max_length=5, null=True, blank=True, default=0)
    decimal_time = models.DecimalField(max_digits=15, decimal_places=3, default=0,  null=True, blank=True)
    score = models.DecimalField(max_digits=15, decimal_places=2, default=0, null=True, blank=True)
    percent = models.DecimalField(max_digits=15, decimal_places=2, default=0, null=True, blank=True)
    evaluator = models.ForeignKey(Instructor, null=True, blank=True, default=None)
def save(self, *args, **kwargs):
    """Sets the raw_time and decimal_time from the minutes and seconds and saves the object."""
    self.raw_time = self.get_raw_time()
    self.decimal_time = self.get_decimal_time()
    self.score = self.get_score()
    super(Evaluation, self).save(*args, **kwargs)
评估的保存方法为:

class Evaluation(models.Model):
    student = models.ForeignKey(StudentRegistration)
    machine_class = models.ForeignKey(MachineClass)
    operational = models.IntegerField()
    minutes = models.IntegerField(null=True, blank=True, default=0)
    seconds = models.IntegerField(null=True, blank=True, default=0)
    raw_time = models.CharField(max_length=5, null=True, blank=True, default=0)
    decimal_time = models.DecimalField(max_digits=15, decimal_places=3, default=0,  null=True, blank=True)
    score = models.DecimalField(max_digits=15, decimal_places=2, default=0, null=True, blank=True)
    percent = models.DecimalField(max_digits=15, decimal_places=2, default=0, null=True, blank=True)
    evaluator = models.ForeignKey(Instructor, null=True, blank=True, default=None)
def save(self, *args, **kwargs):
    """Sets the raw_time and decimal_time from the minutes and seconds and saves the object."""
    self.raw_time = self.get_raw_time()
    self.decimal_time = self.get_decimal_time()
    self.score = self.get_score()
    super(Evaluation, self).save(*args, **kwargs)
获取原始时间方法:

def get_raw_time(self):
    """Formats the minutes and seconds into a time string d:dd and returns the formatted time."""
    s = '0'
    if self.seconds < 10:
        s = s + str(self.seconds)
    else:
        s = self.seconds
    return '%s:%s' % (self.minutes, s)
def get_decimal_time(self):
    return '%.3f' % ((self.minutes) + (self.seconds / 60.0))
def get_best_time(self):
    reg_ary = []
    s_class = self.student.scheduled_class_id
    registrations = StudentRegistration.objects.filter(scheduled_class_id=s_class).values('id')
    for r in registrations:
        reg_ary.append(r['id'])
    evaluations = Evaluation.objects.filter(student_id__in=reg_ary).order_by('decimal_time')
    for e in evaluations:
        if e.machine_class == self.machine_class:
            if e.decimal_time < self.get_decimal_time():
                return '%.3f' % round(e.decimal_time, 4)
            else:
                return '%.3f' % round(self.get_decimal_time(), 4)
    return self.get_decimal_time()
获取最佳时间方法:

def get_raw_time(self):
    """Formats the minutes and seconds into a time string d:dd and returns the formatted time."""
    s = '0'
    if self.seconds < 10:
        s = s + str(self.seconds)
    else:
        s = self.seconds
    return '%s:%s' % (self.minutes, s)
def get_decimal_time(self):
    return '%.3f' % ((self.minutes) + (self.seconds / 60.0))
def get_best_time(self):
    reg_ary = []
    s_class = self.student.scheduled_class_id
    registrations = StudentRegistration.objects.filter(scheduled_class_id=s_class).values('id')
    for r in registrations:
        reg_ary.append(r['id'])
    evaluations = Evaluation.objects.filter(student_id__in=reg_ary).order_by('decimal_time')
    for e in evaluations:
        if e.machine_class == self.machine_class:
            if e.decimal_time < self.get_decimal_time():
                return '%.3f' % round(e.decimal_time, 4)
            else:
                return '%.3f' % round(self.get_decimal_time(), 4)
    return self.get_decimal_time()
以下是数字:

written_test = 21
operational = 96
minutes = 3
seconds = 1
这是表中的第一个条目,因此这是最佳时间,因此当计算分数时,它应该是
21+96=117

当我输入这些数字时,我得到:

117 written to the database # correct maybe, I think it should be 117.00 but not huge.
raw_time = 3:01 # correct
decimal_time = 3.017 # correct
best_decimal_time = 3.017 # correct
score = 117.00 # correct
当我将记录更改为2秒时,我得到:

116.98 written to the database # incorrect, should still be 117
raw_time = 3:02 # correct
decimal_time = 3.033 # correct
best_decimal_time = 3.033 # correct
score = 117.00 # correct
当我删除记录并使用分=3秒=2再次开始时,我得到:

117 written to the database # correct mostly
raw_time = 3:02 # correct
decimal_time = 3.033 # correct
best_decimal_time = 3.033 # correct
score = 117.00 # correct
最后,当我将记录更改为1秒时,我得到:

117.02 written to the database # incorrect, should still be 117
raw_time = 3:01 # correct
decimal_time = 3.017 # correct
best_decimal_time = 3.017 # correct
score = 117.00 # correct
以下是这些值的确切来源:

I looked in the database for the value written there
raw_time = self.raw_time
decimal_time = self.decimal_time
best_decimal_time = self.get_best_time()
score = self.get_score()
我怀疑这是浮点数二进制表示的问题,但似乎无法找到解决方法。我试着用小数点来表示,有些东西不太对劲,我的大脑有点痛。我知道这很长,但我想确保提供尽可能多的相关信息。是不是时间精确到了三位数,分数却没有

让我困惑的是,数据库正在获取写入数据库的值的
get_score()
结果,但界面中显示的内容不同


建议?

好吧,我被浮动问题缠住了,以至于错过了真正的问题。问题是,我需要检查数据库中的最佳时间是否属于当前评估,如果属于当前评估,则使用
self
而不是数据库值


+1到Messa让我思考。

差0.02看起来比二进制浮点表示问题通常要大。这是我最初的想法,但我没有更好的理由解释为什么
get_score()
方法只在编辑时返回两个不同的值……等等,它只是在编辑时,那么,当数据库中的值发生更改时,是什么导致了问题呢。可能有什么事。。。。。