Add an implementation of python2 style round.

Python 3 has no way to access this implementation of rounding in the
standard library.  We implement it here so that we can continue to use
it for grades calculation to keep regrading consistent.

Currently we can't be confident that if we change the rounding behaviour
we won't impact students.  We can't be sure that students that were
previously passing wouldn't suddenly no longer be passing.  Given this,
it's lower risk to just implement the old rounding strategy here and use
it when we are rounding to calculate grades.
This commit is contained in:
Feanil Patel
2019-10-24 15:28:09 -04:00
parent 636037514c
commit ab40748b5a
2 changed files with 37 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
"""
Helpers functions for grades and scores.
"""
import math
def compare_scores(earned1, possible1, earned2, possible2, treat_undefined_as_zero=False):
@@ -42,3 +43,26 @@ def is_score_higher_or_equal(earned1, possible1, earned2, possible2, treat_undef
"""
is_higher_or_equal, _, _ = compare_scores(earned1, possible1, earned2, possible2, treat_undefined_as_zero)
return is_higher_or_equal
def round_away_from_zero(number, digits=0):
"""
Round numbers using the 'away from zero' strategy as opposed to the
'Banker's rounding strategy.' The strategy refers to how we round when
a number is half way between two numbers. eg. 0.5, 1.5, etc. In python 2
positive numbers in this category would be rounded up and negative numbers
would be rounded down. ie. away from zero. In python 3 numbers round
towards even. So 0.5 would round to 0 but 1.5 would round to 2.
See here for more on floating point rounding strategies:
https://en.wikipedia.org/wiki/IEEE_754#Rounding_rules
We want to continue to round away from zero so that student grades remain
consistent and don't suddenly change.
"""
p = 10.0 ** digits
if number >= 0:
return float(math.floor((number * p) + 0.5)) / p
else:
return float(math.ceil((number * p) - 0.5)) / p

View File

@@ -7,7 +7,7 @@ from unittest import TestCase
import ddt
from ..grade_utils import compare_scores
from ..grade_utils import compare_scores, round_away_from_zero
@ddt.ddt
@@ -45,3 +45,15 @@ class TestGradeUtils(TestCase):
assert is_higher is True
assert 0 == percentage_1
assert 0 == percentage_2
@ddt.data(
(0.5, 1),
(1.45, 1.5, 1),
(-0.5, -1.0),
(-0.1, -0.0),
(0.1, 0.0),
(0.0, 0.0)
)
@ddt.unpack
def test_round_away_from_zero(self, precise, expected_rounded_number, rounding_precision=0):
assert round_away_from_zero(precise, rounding_precision) == expected_rounded_number