Определите точность и масштаб конкретного числа в Python

У меня есть переменная в Python, содержащем число с плавающей точкой (например. num = 24654.123), и я хотел бы определить точность числа и значения масштаба (в смысле Oracle), таким образом, 123.45678 должен дать мне (8,5), 12.76 должен дать мне (4,2), и т.д.

Я сначала думал об использовании строкового представления (через str или repr), но они перестали работать для больших количеств (хотя я понимаю теперь, что это - ограничения представления с плавающей точкой, это - проблема здесь):

>>> num = 1234567890.0987654321
>>> str(num) = 1234567890.1
>>> repr(num) = 1234567890.0987654

Править:

Положительные стороны ниже. Я должен разъясниться. Число уже является плаванием и продвигается к базе данных через cx_Oracle. Я пытаюсь приложить все усилия, я могу в Python для обработки плаваний, которые являются слишком большими для соответствующего типа БД за исключением выполнения ВСТАВКИ и обработки ошибок Oracle (потому что я хочу иметь дело с числами поле, не запись, за один раз). Я предполагаю map(len, repr(num).split('.')) я являюсь самым близким, доберется до точности и масштаба плавания?

7
задан mskfisher 7 June 2012 в 13:51
поделиться

6 ответов

Получить количество цифр слева от десятичной точки несложно:

int(log10(x))+1

Количество цифр справа от десятичной точки сложнее из-за присущей неточности чисел с плавающей запятой. ценности. Мне понадобится еще несколько минут, чтобы понять это.

Изменить: Исходя из этого принципа, вот полный код.

import math

def precision_and_scale(x):
    max_digits = 14
    int_part = int(abs(x))
    magnitude = 1 if int_part == 0 else int(math.log10(int_part)) + 1
    if magnitude >= max_digits:
        return (magnitude, 0)
    frac_part = abs(x) - int_part
    multiplier = 10 ** (max_digits - magnitude)
    frac_digits = multiplier + int(multiplier * frac_part + 0.5)
    while frac_digits % 10 == 0:
        frac_digits /= 10
    scale = int(math.log10(frac_digits))
    return (magnitude + scale, scale)
15
ответ дан 6 December 2019 в 06:13
поделиться

Думаю, вам следует рассмотреть возможность использования десятичного типа вместо float . Тип float будет давать ошибки округления, потому что числа представлены внутри в двоичном формате, но многие десятичные числа не имеют точного двоичного представления.

3
ответ дан 6 December 2019 в 06:13
поделиться

(0) Пожалуйста, подтвердите или опровергните: Вам даны плавающие числа для использования, это неизбежно, вы не можете получить данные в десятичном виде, типы данных Oracle включают типы на основе десятичных дробей, и это фундаментальное несоответствие неизбежно. Пожалуйста, объясните любое полное или частичное отрицание.

(1) Ваше замечание "провал для больших чисел" вводит в заблуждение/неактуально/неправильно - вы говорите, что ваша отправная точка - это float, но 1234567890.0987654321 не может быть представлен как float, как показывает результат repr().

(2) Возможно, вы могли бы использовать НОВЫЙ repr (Python 2.7 и 3.1), который обеспечивает минимально возможную точность repr(x), которая все еще удовлетворяет float(repr(x)) == x

Например. старый repr(1.1) выдает "1.1000000000000001", новый repr(1.1) выдает "1.1"

По поводу "Я полагаю, map(len, repr(num).split('.')) - это самое близкое к точности и масштабу float?": Вам нужна стратегия для обработки (a) отрицательных и нулевых чисел (b) чисел типа 1.1e20

Копание в Objects/floatobject.c должно привести к появлению кода на C для нового repr() объекта float, если вам нужно использовать Python 2.6 или более раннюю версию.

(3) Возможно, если бы вы сообщили нам спецификации соответствующих типов данных Oracle, мы могли бы помочь вам разработать проверки для выбора типа, который может содержать данное значение float.

2
ответ дан 6 December 2019 в 06:13
поделиться

В принципе, вы не можете использовать числа с плавающей запятой. Использование десятичного типа может помочь, и если вам нужна действительно большая точность, рассмотрите возможность использования gmpy , порта библиотеки GNU Multiple Precision для Python.

1
ответ дан 6 December 2019 в 06:13
поделиться

Невозможно с переменными с плавающей запятой. Например, ввод

>>> 10.2345

дает:

10.234500000000001

Итак, чтобы получить 6,4 из этого, вам нужно будет найти способ различить пользователя, вводящего 10.2345 и 10.234500000000001 ], что невозможно при использовании поплавков. Это связано со способом хранения чисел с плавающей запятой. Используйте десятичное .

import decimal
a = decimal.Decimal('10.234539048538495')
>>> str(a)
'10.234539048538495'
>>>  (len(str(a))-1, len(str(a).split('.')[1]))
(17,15)
5
ответ дан 6 December 2019 в 06:13
поделиться

кажется, что str - лучший выбор, чем repr :

>>> r=10.2345678
>>> r
10.234567800000001
>>> repr(r)
'10.234567800000001'
>>> str(r)
'10.2345678'
3
ответ дан 6 December 2019 в 06:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: