Files
edx-platform/openedx/core/lib/grade_utils.py
Feanil Patel ab40748b5a 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.
2019-10-31 14:29:57 -04:00

69 lines
2.5 KiB
Python

"""
Helpers functions for grades and scores.
"""
import math
def compare_scores(earned1, possible1, earned2, possible2, treat_undefined_as_zero=False):
"""
Returns a tuple of:
1. Whether the 2nd set of scores is higher than the first.
2. Grade percentage of 1st set of scores.
3. Grade percentage of 2nd set of scores.
If ``treat_undefined_as_zero`` is True, this function will treat
cases where ``possible1`` or ``possible2`` is 0 as if
the (earned / possible) score is 0. If this flag is false,
a ZeroDivisionError is raised.
"""
try:
percentage1 = float(earned1) / float(possible1)
except ZeroDivisionError:
if not treat_undefined_as_zero:
raise
percentage1 = 0.0
try:
percentage2 = float(earned2) / float(possible2)
except ZeroDivisionError:
if not treat_undefined_as_zero:
raise
percentage2 = 0.0
is_higher = percentage2 >= percentage1
return is_higher, percentage1, percentage2
def is_score_higher_or_equal(earned1, possible1, earned2, possible2, treat_undefined_as_zero=False):
"""
Returns whether the 2nd set of scores is higher than the first.
If ``treat_undefined_as_zero`` is True, this function will treat
cases where ``possible1`` or ``possible2`` is 0 as if
the (earned / possible) score is 0. If this flag is false,
a ZeroDivisionError is raised.
"""
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