def extract_number(number_str, decimal=None): #TODO: handle decimal=False/True #TODO: regexp \s*[-+]?\s*[€$%]?[0-9,\.]\+ separators = [] groups = [''] groups_index = 0 sign = None for c in number_str: if c in ['.', ',']: separators.append(c) groups.append('') groups_index += 1 elif c in [' ', '€', '$', '%']: continue elif c in ['+', '-'] and sign is None: sign = c elif c in '1234567890': groups[groups_index] += c if sign is None: sign = '+' else: return None if len(groups) == 0: return None elif len(groups[0]) == 0: if len(''.join(groups)) == 0: return None number = Decimal('%s0.%s' % (sign, ''.join(groups))) precision = len(number.as_tuple().digits) scale = - number.as_tuple().exponent input_type = InputType('numeric', dict(precision=precision, scale=scale)) return number, input_type elif len(groups) == 1: return int(groups[0]), InputType('int') elif len(groups) > 1: number = Decimal('%s%s.%s' % (sign,''.join(groups[0:-1]), groups[-1])) precision = len(number.as_tuple().digits) scale = - number.as_tuple().exponent input_type = InputType('numeric', dict(precision=precision, scale=scale)) return number, input_type else: return None
def _get_precision_scale(self, number): """ :param number: :return: tuple(precision, scale, decimal_number) """ try: decimal_num = Decimal(number) except InvalidOperation: raise Invalid(self.msg or 'Value must be a number enclosed with string') return (len(decimal_num.as_tuple().digits), -(decimal_num.as_tuple().exponent), decimal_num)
def fset(self, d): if d is None: num, denom = None, None else: if isinstance(d, tuple): d = Decimal(d[0]) / d[1] elif isinstance(d, (int, int, str)): d = Decimal(d) elif isinstance(d, float): raise TypeError(("Received a floating-point number {} where a decimal is expected. " + "Use a Decimal, str, or int instead").format(d)) elif not isinstance(d, Decimal): raise TypeError(("Received an unknown type {} where a decimal is expected. " + "Use a Decimal, str, or int instead").format(type(d).__name__)) sign, digits, exp = d.as_tuple() denom = 10 ** max(-exp, 0) denom_basis = getattr(self, "{}_basis".format(denom_name), None) if denom_basis is not None: denom = denom_basis num = int(d * denom) if not ((-MAX_NUMBER < num < MAX_NUMBER) and (-MAX_NUMBER < denom < MAX_NUMBER)): raise ValueError(("The amount '{}' cannot be represented in GnuCash. " + "Either it is too large or it has too many decimals").format(d)) setattr(self, num_name, num) setattr(self, denom_name, denom)
def calc_tax(self, amount, price, related=False): # TODO add currency for calculation of taxes if not isinstance(amount, Decimal): amount = Decimal(str(amount)) if isinstance(price, BaseCurrency): price = price.value elif not isinstance(price, Decimal): price = Decimal(str(price)) if price.as_tuple().exponent > -2: price = price.quantize(Decimal('0.01')) taxes = self.product_tax.select_related('tax') tax_inc_sum = Decimal(1) for tax in taxes: if tax.included: tax_inc_sum += tax.tax.get_rate() # net price of one unit unit_exact = (price / tax_inc_sum).quantize(price) used_taxes = [] net = (amount * unit_exact).quantize(Decimal('0.01')) gross = (amount * unit_exact).quantize(Decimal('0.01')) for tax in taxes: tax_value = (net * tax.tax.get_rate()).quantize(Decimal('0.01')) gross += tax_value if related: used_taxes.append((tax.tax, tax_value, tax)) else: used_taxes.append((tax.tax, tax_value)) return unit_exact, net, gross, used_taxes
def decimal_places(arg): """ Returns the number of decimal places in the given number Parameters ---------- arg: Numeric or string A number to determine the number of decimal places Returns ------- Number of decimal places found. Raises ------ IllegalArgumentException if argument is not numeric. """ if not is_number(str(arg)): raise IllegalArgumentException("[{0}] is not a number".format(arg)) dec = Decimal(str(arg)) exp = dec.as_tuple().exponent result = -exp return result
def latex(self): d = Decimal('%.2e' % self.val) m = d.as_tuple() dig = m[1] exponent = m[2] + 2 s = "-" if m[0] == 1 else "" if (exponent < -3 or exponent > 4): s += (str(dig[0]) + "." + str(dig[1]) + str(dig[2]) + ' \times ' + '10^{' + str(exponent) + '}') return s if exponent >= 2: s += str(dig[0]) + str(dig[1]) + str(dig[2]) for num in range(exponent - 2, 0, -1): s += "0" return s if exponent <= -1: s += "0." for i in range(0, exponent + 1, -1): s += "0" s += str(dig[0]) + str(dig[1]) + str(dig[2]) return s for i in range(3): s += str(dig[i]) if i == exponent: s += "." return s
def __setitem__(self, key, value): try: key = key.upper() except AttributeError: raise AttributeError('Keys stored as upper-case strings: %s unsuitable' % (key)) value = Decimal(value) if key in self.keys() and not 'CURRENT' in key: # Validate choosing more detailed value for variable existing_exp = self[key].as_tuple().exponent # 0.1111 --> -4 candidate_exp = value.as_tuple().exponent if existing_exp > candidate_exp: # candidate has more digits places = Decimal(10) ** (existing_exp + 1) # exp+1 permits slack in rounding best_value = value else: # existing has more digits places = Decimal(10) ** (candidate_exp + 1) best_value = self[key] # Validate values are the same places = max(places, Decimal('1E-11')) # for computed psivars #print('FLOOR: ', self[key].quantize(places, rounding=ROUND_FLOOR) - value.quantize(places, rounding=ROUND_FLOOR)) #print('CEIL: ', self[key].quantize(places, rounding=ROUND_CEILING) - value.quantize(places, rounding=ROUND_CEILING)) if (self[key].quantize(places, rounding=ROUND_CEILING).compare(value.quantize(places, rounding=ROUND_CEILING)) != 0) and \ (self[key].quantize(places, rounding=ROUND_FLOOR).compare(value.quantize(places, rounding=ROUND_FLOOR)) != 0): raise ParsingValidationError( """Output file yielded both %s and %s as values for quantity %s.""" % (self[key].to_eng_string(), value.to_eng_string(), key)) #print 'Resetting variable %s to %s' % (key, best_value.to_eng_string()) else: best_value = value #print 'Setting variable %s to %s' % (key, best_value.to_eng_string()) super(PreservingDict, self).__setitem__(key, best_value)
def get_int_exp(str_n): # makes int from fractional by multiplying by 10 # as much time as needed to get int n = Decimal(str_n) sign, digits, exp = n.as_tuple() int_n = int(n*10**(-exp)) return (abs(int_n), exp)
def html_scientific_notation_rate(rate): """Helper for convert decimal rate using scientific notation. For example we want to show the very detail value of fatality rate because it might be a very small number. :param rate: Rate value :type rate: float :return: Rate value with html tag to show the exponent :rtype: str """ precision = '%.3f' if rate * 100 > 0: decimal_rate = Decimal(precision % (rate * 100)) if decimal_rate == Decimal((precision % 0)): decimal_rate = Decimal(str(rate * 100)) else: decimal_rate = Decimal(str(rate * 100)) if decimal_rate.as_tuple().exponent >= -3: rate_percentage = str(decimal_rate) else: rate = '%.2E' % decimal_rate html_rate = rate.split('E') # we use html tag to show exponent html_rate[1] = '10<sup>{exponent}</sup>'.format( exponent=html_rate[1]) html_rate.insert(1, 'x') rate_percentage = ''.join(html_rate) return rate_percentage
def valor(self, valor): if self.formato == 'alfa': if not isinstance(valor, unicode): try: valor = valor and unicode(valor) or u'' except: raise errors.TipoError(self, valor) if len(valor) > self.digitos: raise errors.NumDigitosExcedidoError(self, valor) elif self.decimais: if not isinstance(valor, Decimal): try: valor = Decimal(valor) except: raise errors.TipoError(self, valor) valor = valor.quantize(Decimal('.' + (self.decimais * '0'))) num_decimais = valor.as_tuple().exponent * -1 if num_decimais != self.decimais: raise errors.NumDecimaisError(self, valor) if len(str(valor).replace('.', '')) > self.digitos: raise errors.NumDigitosExcedidoError(self, valor) else: if not isinstance(valor, (int, long)): raise errors.TipoError(self, valor) if len(str(valor)) > self.digitos: raise errors.NumDigitosExcedidoError(self, valor) self._valor = valor
def format_num(num, decplaces=10): "Converts a number into a more a readable string-version." try: dec = Decimal(num) # Cut the decimal off at "precision" decimal places. if decplaces < 1: dec = dec.quantize(Decimal("0")) else: # Set our precision to at least 28 or twice our precision, lest # Decimal.quantize complains about "result has too many digits". getcontext().prec = max(28, int(decplaces * 2)) dec = dec.quantize(Decimal(".{}".format("0" * decplaces))) except: return "bad" # Split the decimal into sign, digits and exponent. tup = dec.as_tuple() delta = len(tup.digits) + tup.exponent digits = "".join(str(d) for d in tup.digits) # Put the number back together considering the delta. if delta <= 0: zeros = abs(tup.exponent) - len(tup.digits) val = "0." + ("0" * zeros) + digits else: val = digits[:delta] + ("0" * tup.exponent) + '.' + digits[delta:] # Strip trailing 0s and/or trailing dot: val = val.rstrip("0") if val[-1] == ".": val = val[:-1] if tup.sign: return "-" + val return val
def to_mongo(self, document: BaseDocument, value: Decimal) -> dict: sign, digits, exp = value.as_tuple() integer = self._integer_from_digits(digits) return { 'i': -integer if sign else integer, 'e': exp }
def Calc(): for i in range(2, 100): sqrt = Decimal(i).sqrt() digits = sqrt.as_tuple().digits if len(digits) > 5: # Irrational(ish). digitalSum = sum(digits[:100]) yield digitalSum
def sum_of_sqrt_digits(value, digits): if int(sqrt(value))**2 == value: return 0 precision = digits + 2 root = Decimal(value).sqrt(Context(precision)) return sum(root.as_tuple().digits[:digits])
def scientificformat(text): """ Displays a float in scientific notation. If the input float is infinity or NaN, the (platform-dependent) string representation of that value will be displayed. This is based on the floatformat function in django/template/defaultfilters.py """ try: input_val = force_unicode(text) d = Decimal(input_val) except UnicodeEncodeError: return u'' except InvalidOperation: if input_val in special_floats: return input_val try: d = Decimal(force_unicode(float(text))) except (ValueError, InvalidOperation, TypeError, UnicodeEncodeError): return u'' try: m = int(d) - d except (ValueError, OverflowError, InvalidOperation): return input_val try: # for 'normal' sized numbers if d.is_zero(): number = u'0' elif ( (d > Decimal('-100') and d < Decimal('-0.1')) or ( d > Decimal('0.1') and d < Decimal('100')) ) : # this is what the original floatformat() function does sign, digits, exponent = d.quantize(Decimal('.01'), ROUND_HALF_UP).as_tuple() digits = [unicode(digit) for digit in reversed(digits)] while len(digits) <= abs(exponent): digits.append(u'0') digits.insert(-exponent, u'.') if sign: digits.append(u'-') number = u''.join(reversed(digits)) else: # for very small and very large numbers sign, digits, exponent = d.as_tuple() exponent = d.adjusted() digits = [unicode(digit) for digit in digits][:3] # limit to 2 decimal places while len(digits) < 3: digits.append(u'0') digits.insert(1, u'.') if sign: digits.insert(0, u'-') number = u''.join(digits) number += u'e' + u'%i' % exponent return mark_safe(formats.number_format(number)) except InvalidOperation: return input_val
class IssuedAmount: MIN_MANTISSA = 10**15 MAX_MANTISSA = 10**16 - 1 MIN_EXP = -96 MAX_EXP = 80 def __init__(self, strnum): self.context = getcontext() self.context.prec = 15 self.context.Emin = self.MIN_EXP self.context.Emax = self.MAX_EXP self.dec = Decimal(strnum) def to_bytes(self): if self.dec.is_zero(): return self.canonical_zero_serial() # Convert components to integers --------------------------------------- sign, digits, exp = self.dec.as_tuple() mantissa = int("".join([str(d) for d in digits])) # Canonicalize to expected range --------------------------------------- while mantissa < self.MIN_MANTISSA and exp > self.MIN_EXP: mantissa *= 10 exp -= 1 while mantissa > self.MAX_MANTISSA: if exp >= self.MAX_EXP: raise ValueError("amount overflow") mantissa //= 10 exp += 1 if exp < self.MIN_EXP or mantissa < self.MIN_MANTISSA: # Round to zero return self.canonical_zero_serial() if exp > self.MAX_EXP or mantissa > self.MAX_MANTISSA: raise ValueError("amount overflow") # Convert to bytes ----------------------------------------------------- serial = 0x8000000000000000 # "Not XRP" bit set if sign == 0: serial |= 0x4000000000000000 # "Is positive" bit set serial |= ((exp+97) << 54) # next 8 bits are exponent serial |= mantissa # last 54 bits are mantissa return serial.to_bytes(8, byteorder="big", signed=False) def canonical_zero_serial(self): """ Returns canonical format for zero (a special case): - "Not XRP" bit = 1 - Everything else is zeroes - Arguably this means it's canonically written as "negative zero" because the encoding usually uses 1 for positive. """ return (0x8000000000000000).to_bytes(8, byteorder="big", signed=False)
def verify_ogr_field(self, ogr_field, model_field): """ Verifies if the OGR Field contents are acceptable to the Django model field. If they are, the verified value is returned, otherwise the proper exception is raised. """ if isinstance(ogr_field, OFTString) and isinstance(model_field, (models.CharField, models.TextField)): if self.encoding: # The encoding for OGR data sources may be specified here # (e.g., 'cp437' for Census Bureau boundary files). val = force_text(ogr_field.value, self.encoding) else: val = ogr_field.value if model_field.max_length and len(val) > model_field.max_length: raise InvalidString( "%s model field maximum string length is %s, given %s characters." % (model_field.name, model_field.max_length, len(val)) ) elif isinstance(ogr_field, OFTReal) and isinstance(model_field, models.DecimalField): try: # Creating an instance of the Decimal value to use. d = Decimal(str(ogr_field.value)) except DecimalInvalidOperation: raise InvalidDecimal("Could not construct decimal from: %s" % ogr_field.value) # Getting the decimal value as a tuple. dtup = d.as_tuple() digits = dtup[1] d_idx = dtup[2] # index where the decimal is # Maximum amount of precision, or digits to the left of the decimal. max_prec = model_field.max_digits - model_field.decimal_places # Getting the digits to the left of the decimal place for the # given decimal. if d_idx < 0: n_prec = len(digits[:d_idx]) else: n_prec = len(digits) + d_idx # If we have more than the maximum digits allowed, then throw an # InvalidDecimal exception. if n_prec > max_prec: raise InvalidDecimal( "A DecimalField with max_digits %d, decimal_places %d must " "round to an absolute value less than 10^%d." % (model_field.max_digits, model_field.decimal_places, max_prec) ) val = d elif isinstance(ogr_field, (OFTReal, OFTString)) and isinstance(model_field, models.IntegerField): # Attempt to convert any OFTReal and OFTString value to an OFTInteger. try: val = int(ogr_field.value) except ValueError: raise InvalidInteger("Could not construct integer from: %s" % ogr_field.value) else: val = ogr_field.value return val
def test_decimal(): """Test a false positive with decimal.Decimal.as_tuple See astroid https://bitbucket.org/logilab/astroid/issues/92/ """ from decimal import Decimal dec = Decimal(2) first, second, third = dec.as_tuple() return first, second, third
def normalize_decimal(number): new_number = Decimal(str(number)) new_number = new_number.normalize() exponent = new_number.as_tuple()[2] if exponent > 10: new_number = Decimal(0) elif exponent > 0: new_number = new_number.quantize(1) return new_number
def minorTicks(self): # subdivide the major ticks intervals, in 5 majorTicks = self.majorTicks() if len(majorTicks) < 2: return [] trueMin = min(self.scale_min, self.scale_max) trueMax = max(self.scale_min, self.scale_max) if self.log: ticks = [] standardLogTicks = [2, 4, 6, 8] for a in standardLogTicks: if a * majorTicks[0] / 10. >= trueMin: ticks.append(a * majorTicks[0] / 10.) ticks += [a * x for a in standardLogTicks for x in majorTicks] for a in standardLogTicks: if a * majorTicks[-1] <= trueMax: ticks.append(a * majorTicks[-1]) else: majorTickInterval = self.majorTickInterval majorTickIntervalDecimal = Decimal(majorTickInterval) mainDigit = majorTickIntervalDecimal.as_tuple().digits[0] if mainDigit == 1: minorTickDiv = 5 elif mainDigit == 2: minorTickDiv = 4 # could be 2 with another tick subdivision elif mainDigit == 5: minorTickDiv = 5 else: minorTickDiv = 5 minorTickInterval = abs(majorTickInterval / minorTickDiv) # find lowest bound x = majorTicks[0] while x >= trueMin: x -= minorTickInterval x += minorTickInterval # fill up to the max ticks = [] while x <= trueMax: ticks.append(x) x += minorTickInterval return ticks
def pick_coda_from_decimal(decimal): """Picks only a coda from a decimal.""" decimal = Decimal(decimal) __, digits, exp = decimal.as_tuple() if exp < 0: return DIGIT_CODAS[digits[-1]] __, digits, exp = decimal.normalize().as_tuple() index = bisect_right(EXP_INDICES, exp) - 1 if index < 0: return DIGIT_CODAS[digits[-1]] else: return EXP_CODAS[EXP_INDICES[index]]
def normalize_btc_amt(amt): # amt must be a string! from decimal import Decimal try: ret = Decimal(amt) except: msg("%s: Invalid amount" % amt) return False dmsg("Decimal(amt): %s\nAs tuple: %s" % (amt,repr(ret.as_tuple()))) if ret.as_tuple()[-1] < -8: msg("%s: Too many decimal places in amount" % amt) return False if ret == 0: msg("Requested zero BTC amount") return False return trim_exponent(ret)
def isPandigitFirst9(n): print(n) s = Decimal(5).sqrt() p = Decimal((1 + s) / 2) v = Decimal(((p**n) - ((1-p)**n)) / s) sign, digits, exp = v.as_tuple() r = set(digits[:9]) r.discard(0) if len(r) == 9: print(n, r) return True return False
def get_client(self, record, factor=1): value = record.value.get(self.name) if value is not None: digits = self.digits(record, factor=factor) if digits: p = digits[1] else: d = value * factor if not isinstance(d, Decimal): d = Decimal(repr(d)) p = -int(d.as_tuple().exponent) return locale.format('%.*f', (p, value * factor), True) else: return ''
def convert(match): match_item = match.group(match_index) value_item = match.group(value_index) if match_item and value_item: if ')' in match_item and '(' not in match_item: # clear any trailing parenthesis match_item = re.sub('[)]', '', 'match_item') from_value = Decimal(re.sub(r'[^\d.]', '', value_item)) precision = abs(from_value.as_tuple().exponent) to_value = rate * from_value converted_value = to_currency(to_value, places=precision, curr=currency) diff.setdefault(match_item, format_output(match_item, converted_value)) return diff[match_item]
def number_of_decimal_places(n): """ Compute the number of decimal places in a number. Examples -------- >>> number_of_decimal_places(1) 0 >>> number_of_decimal_places(3.14) 2 >>> number_of_decimal_places('3.14') 2 """ decimal = Decimal(str(n)) return -decimal.as_tuple().exponent
def from_decimal(cls, dec): from decimal import Decimal if isinstance(dec, numbers.Integral): dec = Decimal(int(dec)) elif not isinstance(dec, Decimal): raise TypeError('%s.from_decimal() only takes Decimals, not %r (%s)' % (cls.__name__, dec, type(dec).__name__)) if not dec.is_finite(): raise TypeError('Cannot convert %s to %s.' % (dec, cls.__name__)) (sign, digits, exp) = dec.as_tuple() digits = int(''.join(map(str, digits))) if sign: digits = -digits if exp >= 0: return cls(digits*10**exp) return cls(digits, 10**(-exp))
def gen_raw_decimal(val) : from decimal import Decimal assert isinstance(val, (str, int, long, Decimal)) if isinstance(val, (str, int, long)) : val = Decimal(val) sign, digits, exponent = val.as_tuple() mantissa = 0L for digit in digits : mantissa *= 10 mantissa += digit if sign == 1 : mantissa = -mantissa print mantissa, exponent raw_mantissa = raw_int(mantissa) raw_exponent = var_int(exponent) return raw_exponent + raw_mantissa
def _check_amount(self, amount): """ Check the amount (Importe) :param amount: the amount (Importe) :return: True if it have the expected length, otherwise False """ name = 'amount' decimal = Decimal(amount) if decimal.as_tuple().exponent < -2: raise ValueError('{} have more than 2 decimals'.format(name)) if decimal > 99999999.99: raise ValueError('{} is too big'.format(name)) value = unicode(int(decimal * 100)).zfill(10) expected_length = 10 description = 'amount lenth should be 10' return self._check_length(name, value, expected_length, description)
def parse_non_native_amount(string): amount = Decimal(string).normalize() parts = amount.as_tuple() exponent = parts.exponent value = ''.join(map(str, parts.digits)) exponent += len(value) value = value.ljust(16, '0') exponent -= 16 value = int(value) if value == 0: exponent = -99 return parts.sign, value, exponent
def parse_non_native_amount(string): """ """ amount = Decimal(string) # This will remove trailing zeros amount = amount.normalize() parts = amount.as_tuple() offset = parts.exponent # Shift everything such that '10' because '1000000....' value = ''.join(map(str, parts.digits)) full_value = value.ljust(len('9999999999999999'), '0') offset -= len(full_value) - len(value) full_value = int(full_value) # This is special cased if full_value == 0: offset = -100 return parts.sign, full_value, offset
def automagicallyRound(val): # Attempts to fix the rounding issue # Convert to string if type(val) != str: val_str = str(val) else: val_str = val # Try and match m = REGEX.match(val_str) if m: m_dec = Decimal(m[0]) numDecPlaces = m_dec.as_tuple().exponent m_rounded = round(m_dec, abs(numDecPlaces) - 1) val_str = str(m_rounded) # Only removing trailing zeroes if there are numbers after the decimal point (to prevent truncating 1000 etc) if REGEX_FLOAT.match(val_str): val_str = str(REGEX_TRAILING.sub('', val_str)) return val_str
def value(self, value): if value is None: self._value = None return if isinstance(value, Currency): self._value = value.value return if isinstance(value, (int, str, Decimal)): if isinstance(value, str): value = value.upper().strip() if len(value) >= 4 and value[-3:] == "TFT": value = value[:-3].rstrip() d = Decimal(value) sign, _, exp = d.as_tuple() if exp < -9: raise Exception("CurrencyPrecisionOverflow") if sign != 0: raise Exception("Negative currency") self._value = d return raise Exception("cannot set value of type {} as Currency (invalid type)".format(type(value)))
def auto_quantize(number: Decimal, threshold: float) -> Decimal: """Automatically quantize the number at a given threshold. For example, with a threshold of 0.01, this will convert: 20.899999618530273 20.9 20.290000000000000000000000000000 20.29 110.90 110.9 11.0600004196167 11.06 10.539999961853027 10.54 134.3300018310547 134.33 253.920200000000000000000000000000 253.9202 """ exponent = auto_quantized_exponent(number, threshold) if exponent != number.as_tuple().exponent: quant = TEN**exponent qnumber = number.quantize(quant).normalize() return qnumber else: return number
def measureINCH(): inch = vin("Inch measurement", 0.1969, units="in") if (inch == 'q'): return if (inch == 'c'): measureMM() else: try: d = Decimal(inch) except: num, denom = inch.split('/') inch = float(num)/float(denom) d = Decimal(inch) inch = float(inch) mm = inch*25.4 if (d.as_tuple().exponent <= -4): digits = 4 else: digits = 3 print('{0} in = {1} in = {2} mm'.format(inch, tofrac(inch), round(mm,digits))) measureINCH()
def fset(self, d): if d is None: num, denom = None, None else: if isinstance(d, tuple): d = Decimal(d[0]) / d[1] elif isinstance(d, (float, int, long, str)): d = Decimal(d) assert isinstance(d, Decimal) sign, digits, exp = d.as_tuple() denom = 10 ** max(-exp, 0) denom_basis = getattr(self, "{}_basis".format(denom_name), None) if denom_basis is not None: denom = denom_basis num = int(d * denom) setattr(self, num_name, num) setattr(self, denom_name, denom)
def validate(cls, value: Decimal) -> Decimal: digit_tuple, exponent = value.as_tuple()[1:] if exponent in {'F', 'n', 'N'}: raise ValueError(f'value is not a valid decimal, got {value}') if exponent >= 0: # A positive exponent adds that many trailing zeros. digits = len(digit_tuple) + exponent decimals = 0 else: # If the absolute value of the negative exponent is larger than the # number of digits, then it's the same as the number of digits, # because it'll consume all of the digits in digit_tuple and then # add abs(exponent) - len(digit_tuple) leading zeros after the # decimal point. if abs(exponent) > len(digit_tuple): digits = decimals = abs(exponent) else: digits = len(digit_tuple) decimals = abs(exponent) whole_digits = digits - decimals if cls.max_digits is not None and digits > cls.max_digits: raise ValueError( f'ensure that there are no more than {cls.max_digits} digits in total' ) if cls.decimal_places is not None and decimals > cls.decimal_places: raise ValueError( f'ensure that there are no more than {cls.decimal_places} decimal places' ) if cls.max_digits is not None and cls.decimal_places is not None: expected = cls.max_digits - cls.decimal_places if whole_digits > expected: raise ValueError( f'ensure that there are no more than {expected} digits before the decimal point' ) return value
def fmtPricePad(n, padding=10, decimals=4): """Format price with padding as: - two decimal precision if <= 2 decimals - i.e. print 120 as 120.00 print 120.3 as 120.30 - up to 4 decimal places if more than 2 (as formatted by 'g') Rounding is done by round() and Decimal() then printed via .f or .g Also has a check to ignore very small values taking up wide space.""" # python formatting doesn't allow 0 padding padding = max(padding, 1) # don't show tiny tiny values, and use 'abs' because sometimes # we're printing full negative percentages like -20.3242343289%, which is # les sthan 0.005, but we want to still print them nicely. # also guard against 'n' being None for some reason. if (not n) or abs(n) < 0.005: if n: return f"{n:>{padding},.2f}" return f"{' ':>{padding}}" # print at most 4 digits, not ending in zeroes... dn = Decimal(str(round(n, decimals))) sign, digits, exponent = dn.as_tuple() # skip formatting nan if exponent == "n": return f"{dn:>{padding}}" # if less than 3 decimals, always use two places. if abs(exponent) < 3: return f"{dn:>{padding},.2f}" # this long G is okay because we already truncated # the float value to 4 decimals at most using the triple conversion # above of Decimal(str(round(x, 4))) return f"{dn:>{padding},.20g}"
def to(self, type_var): # noqa: C901 import dateutil.parser if type_var.type_id == TypeID.DATE: return DateLiteral( (dateutil.parser.parse(self.value) - Literals.EPOCH).days) elif type_var.type_id == TypeID.TIME: return TimeLiteral( int((dateutil.parser.parse( Literals.EPOCH.strftime("%Y-%m-%d ") + self.value) - Literals.EPOCH).total_seconds() * 1000000)) elif type_var.type_id == TypeID.TIMESTAMP: timestamp = dateutil.parser.parse(self.value) EPOCH = Literals.EPOCH if bool(timestamp.tzinfo) != bool(type_var.adjust_to_utc): raise RuntimeError("Cannot convert to %s when string is: %s" % (type_var, self.value)) if timestamp.tzinfo is not None: EPOCH = EPOCH.replace(tzinfo=pytz.UTC) return TimestampLiteral( int((timestamp - EPOCH).total_seconds() * 1000000)) elif type_var.type_id == TypeID.STRING: return self elif type_var.type_id == TypeID.UUID: return UUIDLiteral(uuid.UUID(self.value)) elif type_var.type_id == TypeID.DECIMAL: dec_val = Decimal(str(self.value)) if abs(dec_val.as_tuple().exponent) == type_var.scale: if type_var.scale == 0: return DecimalLiteral( Decimal(str(self.value)).quantize( Decimal('1.'), rounding=ROUND_HALF_UP)) else: return DecimalLiteral( Decimal(str(self.value)).quantize( Decimal("." + "".join( ["0" for i in range(1, type_var.scale)]) + "1"), rounding=ROUND_HALF_UP))
def clean(self, value): """ Validates that the input is a decimal number. Returns a Decimal instance. Returns None for empty values. Ensures that there are no more than max_digits in the number, and no more than decimal_places digits after the decimal point. """ super(DecimalField, self).clean(value) if not self.required and value in EMPTY_VALUES: return None value = smart_str(value).strip() try: value = Decimal(value) except DecimalException: raise ValidationError(self.error_messages['invalid']) sign, digittuple, exponent = value.as_tuple() decimals = abs(exponent) # digittuple doesn't include any leading zeros. digits = len(digittuple) if decimals > digits: # We have leading zeros up to or past the decimal point. Count # everything past the decimal point as a digit. We do not count # 0 before the decimal point as a digit since that would mean # we would not allow max_digits = decimal_places. digits = decimals whole_digits = digits - decimals if self.max_value is not None and value > self.max_value: raise ValidationError(self.error_messages['max_value'] % self.max_value) if self.min_value is not None and value < self.min_value: raise ValidationError(self.error_messages['min_value'] % self.min_value) if self.max_digits is not None and digits > self.max_digits: raise ValidationError(self.error_messages['max_digits'] % self.max_digits) if self.decimal_places is not None and decimals > self.decimal_places: raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places) if self.max_digits is not None and self.decimal_places is not None and whole_digits > (self.max_digits - self.decimal_places): raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) return value
def get_number_as_fraction(expr, context): literal = Decimal(expr.value) sign, digits, exponent = literal.as_tuple() if exponent < -10: raise InvalidLiteral( f"`decimal` literal cannot have more than 10 decimal places: {literal}", expr) sign = -1 if sign == 1 else 1 # Positive Decimal has `sign` of 0, negative `sign` of 1 # Decimal `digits` is a tuple of each digit, so convert to a regular integer top = int(Decimal((0, digits, 0))) top = sign * top * 10**(exponent if exponent > 0 else 0 ) # Convert to a fixed point integer bottom = 1 if exponent > 0 else 10**abs( exponent) # Make denominator a power of 10 assert Decimal(top) / Decimal(bottom) == literal # Sanity check # TODO: Would be best to raise >10 decimal place exception here # (unless Decimal is used more widely) return expr.node_source_code, top, bottom
def from_decimal(cls, dec): """Converts a finite Decimal instance to a rational number, exactly.""" from decimal import Decimal if isinstance(dec, numbers.Integral): dec = Decimal(int(dec)) elif not isinstance(dec, Decimal): raise TypeError( "%s.from_decimal() only takes Decimals, not %r (%s)" % (cls.__name__, dec, type(dec).__name__)) if dec.is_infinite(): raise OverflowError( "Cannot convert %s to %s." % (dec, cls.__name__)) if dec.is_nan(): raise ValueError("Cannot convert %s to %s." % (dec, cls.__name__)) sign, digits, exp = dec.as_tuple() digits = int(''.join(map(str, digits))) if sign: digits = -digits if exp >= 0: return cls(digits * 10 ** exp) else: return cls(digits, 10 ** -exp)
def validate_NUMPLACES(in_value, restriction): """ the value parameter must be either a single value or a 1-dimensional list. All the values in this list must satisfy the condition """ #Sometimes restriction values can accidentally be put in the template <item>100</items>, #Making them a list, not a number. Rather than blowing up, just get value 1 from the list. if type(restriction) is list: restriction = restriction[0] value = _get_val(in_value) if type(value) is list: for subval in value: if type(subval) is tuple: subval = subval[1] validate_NUMPLACES(subval, restriction) else: restriction = int(restriction) # Just in case.. dec_val = Decimal(str(value)) num_places = dec_val.as_tuple().exponent * -1 #exponent returns a negative num if restriction != num_places: raise ValidationError("NUMPLACES: %s"%(restriction))
def convert(match): match_item = match.group(match_index) value_item = match.group(value_index) suffix_item = match.group(suffix_index) if match_item and value_item: if ')' in match_item and '(' not in match_item: # clear any trailing parenthesis match_item = re.sub('[)]', '', match_item) from_value = Decimal(re.sub(r'[^\d.]', '', value_item)) precision = abs(from_value.as_tuple().exponent) to_value = rate * from_value to_value, suffix_item, precision = update_suffix( to_value, suffix_item, precision) converted_value = to_currency(to_value, places=precision, curr=currency) diff.setdefault( match_item, format_output(match_item, converted_value, suffix_item, src_currency)) return diff[match_item]
def _pseudonymise_DS(value): """ Keep sign and exponent, but hash the digits and then convert the same number of digits from the hash back in to the decimal digits Parameters ---------- value : decimal string A decimal string meeting the spec from DICOM Returns ------- str a decimal string of the same sign and exponent. """ my_decimal = Decimal(value) as_tuple = my_decimal.as_tuple() digits = as_tuple.digits count_digits = len(digits) my_hash_func = hashlib.new("sha3_256") encoded_value = digits.encode("ASCII") my_hash_func.update(encoded_value) # my_digest = my_hash_func.digest() my_hex_digest = my_hash_func.hex_digest() sliced_digest = my_hex_digest[0:count_digits] my_integer = int(sliced_digest, 16) my_integer_string = str(my_integer) # string_count = len(my_integer_string) new_digits = list() for i in range(0, count_digits): new_digits.append(my_integer_string[i : i + 1]) new_decimal_tuple = DecimalTuple( as_tuple.sign, tuple(new_digits), as_tuple.exponent ) new_decimal = Decimal(new_decimal_tuple) return str(new_decimal)
def complement_from_employment(self, employee_obj, **kwargs): """ Update Employee object, get data from employee.employment :param employee_obj: Employee model instance :param kwargs: data params :return: """ obj = employee_obj try: salary = Decimal(kwargs['salary'].replace(',', '')) \ if kwargs['salary'] else Decimal(0) if len(salary.as_tuple().digits) > 10: # if count of digits more 10 - don't save in db salary = Decimal(0) obj.monthlysalary = salary except InvalidOperation: pass obj.extra['title'] = kwargs['position'] or '---' if 'documents' not in obj.extra: obj.extra['documents'] = {} obj.extra['documents'].update({ 'visa': { 'number': kwargs['visa_number'], 'expiry_date': kwargs['visa_expiry_date'], 'image_url': kwargs['visa_document'], }, 'work_contract': { 'start_date': kwargs['contract_start_date'], 'end_date': kwargs['contract_end_date'], }, }) extra_legacy = self.get_extra_legacy(kwargs, 'employment') obj.extra['legacy'].update({'employment': extra_legacy}) obj.extra = self.clean_and_validate_extra(obj.extra) obj.save(metadata=Metadata.empty()) return obj
def decimal_to_string(value: decimal.Decimal) -> str: """ Convert a Decimal value to a string representation that not includes exponent and with its decimals. """ sign, digits, exponent = value.as_tuple() if not exponent: result = ''.join(str(x) for x in digits) elif exponent > 0: result = ''.join(str(x) for x in digits) + '0' * exponent else: result = ''.join(str(x) for x in digits[:exponent]) if not result: result = '0' result += '.' if len(digits) >= -exponent: result += ''.join(str(x) for x in digits[exponent:]) else: result += '0' * (-exponent - len(digits)) result += ''.join(str(x) for x in digits) return '-' + result if sign else result
def value(self, value): if value is None: self._value = None return if isinstance(value, Currency): self._value = value.value return if isinstance(value, (int, str, Decimal)): if isinstance(value, str): value = value.upper().strip() if len(value) >= 4 and value[-3:] == "TFT": value = value[:-3].rstrip() d = Decimal(value) sign, _, exp = d.as_tuple() if exp < -9: raise j.clients.tfchain.errors.CurrencyPrecisionOverflow(d) if sign != 0: raise j.clients.tfchain.errors.CurrencyNegativeValue(d) self._value = d return raise TypeError( "cannot set value of type {} as Currency (invalid type)".format( type(value)))
def _key_validate(self,char,index,current,proposed,action,**kwargs): valid=True min_val=self.cget('from') max_val=self.cget('to') no_negative=min_val>=0 no_decimal=self.precision >= 0 if action =='0': return True #First, filter out obviously invalid keystrokes if any([(char not in('-12345678.')),(char =='-' and (no_negative or index!='0')),(char=='.' and (no_decimal or '.' in current))]): return False #At this point, proposed is either '-','.','-.', or a valid Decimal String if proposed in '-.': return True #Proposed is a valid Decimal String convert to Decimal and Check more: proposed = Decimal(proposed) proposed_precision=proposed.as_tuple().exponent if any([(proposed>max_val),(proposed_precision<self.precision)]): return False return valid
def fmt_prob(prob, prec=4): """ Format a float as a string in a style suitable for displaying probabilities. This is not a particularly quick procedure. If you need to format lots of probabilities, it's probably best to do something cruder. """ from decimal import Decimal # Quantize the value to the correct precision prob = Decimal(str(prob)) #.as_tuple() quant = Decimal((0, [ 1, ], prob.adjusted() - prec + 1)) prob = prob.quantize(quant) # Format it yourself, because Decimal's to_sci_string is crap tup = prob.as_tuple() sci_str = "%s%d.%se%d" % ("-" if prob.is_signed() else "", tup.digits[0], "".join(["%d" % dig for dig in tup.digits[1:] ]), prob.adjusted()) # Add more spacing for higher precisions #fmt_str = " >%ds" % (prec+3) return sci_str #format(sci_str, fmt_str)
def general_format(x, precision: int = 2, pad: int = 10, left: bool = False, fmt: str = 'D') -> str: """General formatter. Parameters ---------- x: str The number (string castable) to be formatted precision: int The precision of the formatter. In sig figs pad: int The amount to pad the string to left_pad: bool If False will right pad the string, fmt: str The delimiting string between the # and the exp Returns ------- str The formatted number as a string """ x = Decimal(str(x)) tup = x.as_tuple() digits = list(tup.digits[:precision + 1]) sign = '-' if tup.sign else '+' dec = ''.join(map(str, digits[1:])) exp = x.adjusted() ret = f'{sign}{digits[0]}.{dec}{fmt}{exp}' if not pad: return ret if not left: return ret.rjust(pad) return ret.ljust(pad)
def format_number(num): """ https://stackoverflow.com/a/5808014/827526 """ try: dec = Decimal(num) except decimal.DecimalException as ex: print(str(ex)) # return f'Bad number. Not a decimal: {num}' return "nan" tup = dec.as_tuple() delta = len(tup.digits) + tup.exponent digits = ''.join(str(d) for d in tup.digits) if delta <= 0: zeros = abs(tup.exponent) - len(tup.digits) val = '0.' + ('0' * zeros) + digits else: val = digits[:delta] + ('0' * tup.exponent) + '.' + digits[delta:] val = val.rstrip('0') if val[-1] == '.': val = val[:-1] if tup.sign: return '-' + val return val
def to_digits_count(number: float, *, max_digits_count: int = FLOATING_POINT_PRECISION) -> float: decimal = Decimal(number).normalize() _, significant_digits, exponent = decimal.as_tuple() significant_digits_count = len(significant_digits) if exponent < 0: fixed_digits_count = (1 - exponent if exponent <= -significant_digits_count else significant_digits_count) else: fixed_digits_count = exponent + significant_digits_count if fixed_digits_count <= max_digits_count: return number whole_digits_count = max(significant_digits_count + exponent, 0) if whole_digits_count: whole_digits_offset = max(whole_digits_count - max_digits_count, 0) decimal /= 10**whole_digits_offset whole_digits_count -= whole_digits_offset else: decimal *= 10**(-exponent - significant_digits_count) whole_digits_count = 1 decimal = round(decimal, max(max_digits_count - whole_digits_count, 0)) return float(str(decimal))
def format_satoshis(x, is_diff=False, num_zeros=0, decimal_point=8, whitespaces=False): from decimal import Decimal s = Decimal(x) sign, digits, exp = s.as_tuple() digits = map(str, digits) while len(digits) < decimal_point + 1: digits.insert(0, '0') digits.insert(-decimal_point, '.') s = ''.join(digits).rstrip('0') if sign: s = '-' + s elif is_diff: s = "+" + s p = s.find('.') s += "0" * (1 + num_zeros - (len(s) - p)) if whitespaces: s += " " * (1 + decimal_point - (len(s) - p)) s = " " * (13 - decimal_point - (p)) + s return s
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from fractions import Fraction from decimal import Decimal from math import factorial, ceil f = 39.9 print(f) print("{0:.2f}".format(f)) i = 3990 print(i) f = Fraction("3.1415926535897932").limit_denominator(1000) print(f) d = Decimal(12345.6789) print(d.as_tuple()) print(round(d, 2)) print(ceil(d)) f = factorial(5) print(f) print(2 ** 3) print(8 // 3)
def format(number, decimal_sep, decimal_pos=None, grouping=0, thousand_sep='', force_grouping=False, use_l10n=None): """ Get a number (as a number or string), and return it as a string, using formats defined as arguments: * decimal_sep: Decimal separator symbol (for example ".") * decimal_pos: Number of decimal positions * grouping: Number of digits in every group limited by thousand separator. For non-uniform digit grouping, it can be a sequence with the number of digit group sizes following the format used by the Python locale module in locale.localeconv() LC_NUMERIC grouping (e.g. (3, 2, 0)). * thousand_sep: Thousand separator symbol (for example ",") """ use_grouping = (use_l10n or (use_l10n is None and settings.USE_L10N)) and settings.USE_THOUSAND_SEPARATOR use_grouping = use_grouping or force_grouping use_grouping = use_grouping and grouping != 0 # Make the common case fast if isinstance(number, int) and not use_grouping and not decimal_pos: return mark_safe(number) # sign sign = '' if isinstance(number, Decimal): if decimal_pos is not None: # If the provided number is too small to affect any of the visible # decimal places, consider it equal to '0'. cutoff = Decimal('0.' + '1'.rjust(decimal_pos, '0')) if abs(number) < cutoff: number = Decimal('0') # Format values with more than 200 digits (an arbitrary cutoff) using # scientific notation to avoid high memory usage in {:f}'.format(). _, digits, exponent = number.as_tuple() if abs(exponent) + len(digits) > 200: number = '{:e}'.format(number) coefficient, exponent = number.split('e') # Format the coefficient. coefficient = format( coefficient, decimal_sep, decimal_pos, grouping, thousand_sep, force_grouping, use_l10n, ) return '{}e{}'.format(coefficient, exponent) else: str_number = '{:f}'.format(number) else: str_number = str(number) if str_number[0] == '-': sign = '-' str_number = str_number[1:] # decimal part if '.' in str_number: int_part, dec_part = str_number.split('.') if decimal_pos is not None: dec_part = dec_part[:decimal_pos] else: int_part, dec_part = str_number, '' if decimal_pos is not None: dec_part = dec_part + ('0' * (decimal_pos - len(dec_part))) dec_part = dec_part and decimal_sep + dec_part # grouping if use_grouping: try: # if grouping is a sequence intervals = list(grouping) except TypeError: # grouping is a single value intervals = [grouping, 0] active_interval = intervals.pop(0) int_part_gd = '' cnt = 0 for digit in int_part[::-1]: if cnt and cnt == active_interval: if intervals: active_interval = intervals.pop(0) or active_interval int_part_gd += thousand_sep[::-1] cnt = 0 int_part_gd += digit cnt += 1 int_part = int_part_gd[::-1] return sign + int_part + dec_part
def verify_ogr_field(self, ogr_field, model_field): """ Verifies if the OGR Field contents are acceptable to the Django model field. If they are, the verified value is returned, otherwise the proper exception is raised. """ if (isinstance(ogr_field, OFTString) and isinstance(model_field, (models.CharField, models.TextField))): if self.encoding: # The encoding for OGR data sources may be specified here # (e.g., 'cp437' for Census Bureau boundary files). val = force_text(ogr_field.value, self.encoding) else: val = ogr_field.value if model_field.max_length and len( val) > model_field.max_length: raise InvalidString( '%s model field maximum string length is %s, given %s characters.' % (model_field.name, model_field.max_length, len(val))) elif isinstance(ogr_field, OFTReal) and isinstance( model_field, models.DecimalField): try: # Creating an instance of the Decimal value to use. d = Decimal(str(ogr_field.value)) except: raise InvalidDecimal('Could not construct decimal from: %s' % ogr_field.value) # Getting the decimal value as a tuple. dtup = d.as_tuple() digits = dtup[1] d_idx = dtup[2] # index where the decimal is # Maximum amount of precision, or digits to the left of the decimal. max_prec = model_field.max_digits - model_field.decimal_places # Getting the digits to the left of the decimal place for the # given decimal. if d_idx < 0: n_prec = len(digits[:d_idx]) else: n_prec = len(digits) + d_idx # If we have more than the maximum digits allowed, then throw an # InvalidDecimal exception. if n_prec > max_prec: raise InvalidDecimal( 'A DecimalField with max_digits %d, decimal_places %d must round to an absolute value less than 10^%d.' % (model_field.max_digits, model_field.decimal_places, max_prec)) val = d elif isinstance(ogr_field, (OFTReal, OFTString)) and isinstance( model_field, models.IntegerField): # Attempt to convert any OFTReal and OFTString value to an OFTInteger. try: val = int(ogr_field.value) except: raise InvalidInteger('Could not construct integer from: %s' % ogr_field.value) else: val = ogr_field.value return val
def floatformat(text, arg=-1): """ Displays a float to a specified number of decimal places. If called without an argument, it displays the floating point number with one decimal place -- but only if there's a decimal place to be displayed: * num1 = 34.23234 * num2 = 34.00000 * num3 = 34.26000 * {{ num1|floatformat }} displays "34.2" * {{ num2|floatformat }} displays "34" * {{ num3|floatformat }} displays "34.3" If arg is positive, it will always display exactly arg number of decimal places: * {{ num1|floatformat:3 }} displays "34.232" * {{ num2|floatformat:3 }} displays "34.000" * {{ num3|floatformat:3 }} displays "34.260" If arg is negative, it will display arg number of decimal places -- but only if there are places to be displayed: * {{ num1|floatformat:"-3" }} displays "34.232" * {{ num2|floatformat:"-3" }} displays "34" * {{ num3|floatformat:"-3" }} displays "34.260" If the input float is infinity or NaN, the (platform-dependent) string representation of that value will be displayed. """ try: input_val = repr(text) d = Decimal(input_val) except InvalidOperation: try: d = Decimal(str(float(text))) except (ValueError, InvalidOperation, TypeError): return '' try: p = int(arg) except ValueError: return input_val try: m = int(d) - d except (ValueError, OverflowError, InvalidOperation): return input_val if not m and p < 0: return mark_safe(formats.number_format('%d' % (int(d)), 0)) if p == 0: exp = Decimal(1) else: exp = Decimal('1.0') / (Decimal(10)**abs(p)) # Set the precision high enough to avoid an exception (#15789). tupl = d.as_tuple() units = len(tupl[1]) units += -tupl[2] if m else tupl[2] prec = abs(p) + units + 1 # Avoid conversion to scientific notation by accessing `sign`, `digits`, # and `exponent` from Decimal.as_tuple() directly. sign, digits, exponent = d.quantize(exp, ROUND_HALF_UP, Context(prec=prec)).as_tuple() digits = [str(digit) for digit in reversed(digits)] while len(digits) <= abs(exponent): digits.append('0') digits.insert(-exponent, '.') if sign: digits.append('-') number = ''.join(reversed(digits)) return mark_safe(formats.number_format(number, abs(p)))
class Manager: model: Linear precision: Optional[Decimal] = None storage: str errors: List[Decimal] def __init__(self, storage: str, learning_rate: Optional[Decimal] = None): """ :param storage: file for coefficients :param learning_rate: coefficient for training """ try: self.model = Linear(learning_rate) except base_reg.InvalidRegression as ex: raise InvalidModel(str(ex)) self.storage = storage if not os.path.isfile(self.storage): self._reset_file() self.errors = [] def load(self): """ load coefficients from file :return: """ coeffs = dict() with open(self.storage, 'r') as storage: line = storage.readline() try: coeffs = json.loads(line) except json.decoder.JSONDecodeError: self._reset_file() if 'coefficients' not in coeffs: raise InvalidModel( 'Coefficients aren`t set, you should train your model' ) try: self.model.set_thetas([Decimal(x) for x in coeffs['coefficients']]) if 'precision' in coeffs: self.precision = Decimal(coeffs['precision']) except (InvalidOperation, base_reg.InvalidRegression): raise InvalidData('Coefficients aren`t valid') def predict(self, x_value: Decimal) -> Prediction: """ :param x_value: request for prediction :return: predicted result by precision of request value; precision """ x_prec = -x_value.as_tuple().exponent row_result = self.model.func(x_value) y_prec = self._get_round_factor() return Prediction( x=x_value, y=round(row_result, x_prec), y_with_precision=round(row_result, y_prec) if y_prec else None, precision=round(self.precision, y_prec) if y_prec else None, ) def plot_errors(self): plt.title('RMS errors') plt.xlabel('training iterations') plt.ylabel('log(errors)') plt.plot(range(len(self.errors)), [math.log(er) for er in self.errors], color='r') def plot_function(self, data: Data): """ :param data: plot function by trained coefficients """ plt.xlabel(data.x_alias) plt.ylabel(data.y_alias) plt.plot( data.x_boarders, [ self.model.func(data.x_boarders[0]), self.model.func(data.x_boarders[1]), ], color='k', ) def train(self, data: Data, iterations: int): """ Dump calculated coefficients to storage :param data: preloaded Data for training :param iterations: number of training iterations """ xs = data.normalize_xs() for i in range(iterations): self.model.one_round(xs, data.points_y) errors = [ self.model.loss(x, y) for x, y in zip(xs, data.points_y) ] self.errors.append(Decimal(math.sqrt(sum(errors) / len(xs)))) self.model.rescale_thetas(data.x_norm_coeff, data.x_boarders[0]) if not self.errors: raise InvalidModel('Too few training iterations') self.precision = self.errors[-1] self._dump() def _get_round_factor(self) -> Optional[int]: if not self.precision: return None prec = self.precision.as_tuple() return -len(prec.digits) - prec.exponent + 1 def _dump(self): f = open(self.storage, 'w') coefficients = { 'coefficients': [str(x) for x in self.model.thetas], 'precision': str(self.precision), } f.write(json.dumps(coefficients)) def _reset_file(self): with open(self.storage, 'w') as storage: storage.write('{}') print(f'-> Reset file "{self.storage}"')
def floatformat(text, arg=-1): """ Display a float to a specified number of decimal places. If called without an argument, display the floating point number with one decimal place -- but only if there's a decimal place to be displayed: * num1 = 34.23234 * num2 = 34.00000 * num3 = 34.26000 * {{ num1|floatformat }} displays "34.2" * {{ num2|floatformat }} displays "34" * {{ num3|floatformat }} displays "34.3" If arg is positive, always display exactly arg number of decimal places: * {{ num1|floatformat:3 }} displays "34.232" * {{ num2|floatformat:3 }} displays "34.000" * {{ num3|floatformat:3 }} displays "34.260" If arg is negative, display arg number of decimal places -- but only if there are places to be displayed: * {{ num1|floatformat:"-3" }} displays "34.232" * {{ num2|floatformat:"-3" }} displays "34" * {{ num3|floatformat:"-3" }} displays "34.260" If arg has the 'g' suffix, force the result to be grouped by the THOUSAND_SEPARATOR for the active locale. When the active locale is en (English): * {{ 6666.6666|floatformat:"2g" }} displays "6,666.67" * {{ 10000|floatformat:"g" }} displays "10,000" If the input float is infinity or NaN, display the string representation of that value. """ force_grouping = False if isinstance(arg, str) and arg.endswith('g'): force_grouping = True arg = arg[:-1] or -1 try: input_val = repr(text) d = Decimal(input_val) except InvalidOperation: try: d = Decimal(str(float(text))) except (ValueError, InvalidOperation, TypeError): return '' try: p = int(arg) except ValueError: return input_val try: m = int(d) - d except (ValueError, OverflowError, InvalidOperation): return input_val if not m and p < 0: return mark_safe( formats.number_format('%d' % (int(d)), 0, force_grouping=force_grouping), ) exp = Decimal(1).scaleb(-abs(p)) # Set the precision high enough to avoid an exception (#15789). tupl = d.as_tuple() units = len(tupl[1]) units += -tupl[2] if m else tupl[2] prec = abs(p) + units + 1 # Avoid conversion to scientific notation by accessing `sign`, `digits`, # and `exponent` from Decimal.as_tuple() directly. rounded_d = d.quantize(exp, ROUND_HALF_UP, Context(prec=prec)) sign, digits, exponent = rounded_d.as_tuple() digits = [str(digit) for digit in reversed(digits)] while len(digits) <= abs(exponent): digits.append('0') digits.insert(-exponent, '.') if sign and rounded_d: digits.append('-') number = ''.join(reversed(digits)) return mark_safe( formats.number_format(number, abs(p), force_grouping=force_grouping), )