Почему мой код не выдает точные выходные данные 2 и 1? - PullRequest
0 голосов
/ 30 января 2020

Я использую Python 3.8

По сути, учитывая набор значений x и y, я написал кое-что, что дает мне приближение с использованием линейной регрессии, но для экспоненциальных моделей. Мне интересно, потому что ожидаемый результат 2 1 на 100% точен, что я сделал специально. Я выбрал полномочия 2. Первая версия программы дает мне примерно 99.99999% точного ответа, но вторая дает мне 100% точный ответ. Кто-нибудь может сказать мне, почему это? Кроме того, мне интересно, является ли log2 в целом более точным в использовании, чем log10, или это просто «случайность» из-за указанных значений c, которые были у меня в points Кроме того, я посмотрел на поле «Похожие вопросы» и ничего не подошло, что казалось похожим на мой вопрос.

Версия 1:

from math import log10, exp
from decimal import Decimal


points = {'1': '2', '2': '4', '5': '32', '6': '64'}
t = Decimal(str(len(points)))
p = Decimal('0')
q = Decimal('0')
r = Decimal('0')
s = Decimal('0')
for key, value in points.items():
    p += Decimal(key)
    q += Decimal(key) * Decimal(key)
    r += Decimal(log10(Decimal(value)))
    s += Decimal(key) * Decimal(log10(Decimal(value)))
a = (t * s - p * r) / (t * q - p * p)
b = (r - a * p) / t
a = Decimal(Decimal('10') ** a)
b = Decimal(Decimal('10') ** b)
print(a, b)

Вот результат, который я получил:

1.999999999999999960280230758 1.000000000000000060150187915

Версия 2:

from math import log2
from decimal import Decimal


points = {'1': '2', '2': '4', '5': '32', '6': '64'}
t = Decimal(str(len(points)))
p = Decimal('0')
q = Decimal('0')
r = Decimal('0')
s = Decimal('0')
for key, value in points.items():
    p += Decimal(key)
    q += Decimal(key) * Decimal(key)
    r += Decimal(log2(Decimal(value)))
    s += Decimal(key) * Decimal(log2(Decimal(value)))
a = (t * s - p * r) / (t * q - p * p)
b = (r - a * p) / t
a = Decimal(Decimal('2') ** a)
b = Decimal(Decimal('2') ** b)
print(a, b)

Вот результат, который я получил:

2 1

Я попробовал другой тест со значениями, которые не являются степенями 10 или 2, но я не знаю, какой из них более точный:

from math import log2, log10
from decimal import Decimal


points = {'1': '3', '2': '7', '5': '26', '6': '62'}
t = Decimal(str(len(points)))
p = Decimal('0')
q = Decimal('0')
r = Decimal('0')
s = Decimal('0')
for key, value in points.items():
    p += Decimal(key)
    q += Decimal(key) * Decimal(key)
    r += Decimal(log2(Decimal(value)))
    s += Decimal(key) * Decimal(log2(Decimal(value)))
a = (t * s - p * r) / (t * q - p * p)
b = (r - a * p) / t
a = Decimal(Decimal('2') ** a)
b = Decimal(Decimal('2') ** b)
print(a, b)


points = {'1': '3', '2': '7', '5': '26', '6': '62'}
t = Decimal(str(len(points)))
p = Decimal('0')
q = Decimal('0')
r = Decimal('0')
s = Decimal('0')
for key, value in points.items():
    p += Decimal(key)
    q += Decimal(key) * Decimal(key)
    r += Decimal(log10(Decimal(value)))
    s += Decimal(key) * Decimal(log10(Decimal(value)))
a = (t * s - p * r) / (t * q - p * p)
b = (r - a * p) / t
a = Decimal(Decimal('10') ** a)
b = Decimal(Decimal('10') ** b)
print(a, b)

Мой результат:

1.752690522119211309696792535 1.902951630457180834208048103
1.752690522119211322362489659 1.902951630457180751134992738

Ответы [ 2 ]

0 голосов
/ 30 января 2020

Я не знаю ни одной математической причины, по которой log2 произвольного числа (целого или нет) с большей вероятностью приведет к иррациональному числу - и, следовательно, к потере точности - чем log10 или любой другой журнал. К сожалению, всегда будет некоторая потеря точности, если результаты каждого вычисления не окажутся рациональными (мощности базы лога).

Вы можете проверить потерю точности, связанную с получением логарифмов для определенного c ряд данных, подобный этому:

def test_precisions(iterable):
    precision_tests = {  # take the log and reverse, several ways
        "ln": lambda n: n.ln().exp(),
        "log10": lambda n: Decimal(10) ** n.log10(),
        "log2": lambda n: Decimal(2) ** (n.ln() / Decimal(2).ln()),
        "math.log2": lambda n: Decimal(2) ** Decimal(log2(n))
        }
    L = list(iterable)
    print('\nTesting {}, {}, {}...{}'.format(L[0], L[1], L[2], L[-1]))

    # Report average loss of precision from each log and reverse function
    # over the numbers in the range
    for name, test in precision_tests.items():
        print(name, sum(test(n) - n for n in L) / len(L))

def dec_range(start, stop, step=1):
    """ Like `range` but yields decimals """
    start = Decimal(start)
    stop = Decimal(stop)
    step = Decimal(step)
    steps = int((stop - start) / step)
    for i in range(steps):
        yield start + i * step

test_precisions(dec_range(1, 1000, 10))  # ln seems best
test_precisions(dec_range(1, 100))       # ln seems best
test_precisions(dec_range(1, 100, '.1')) # log10 seems best
test_precisions(dec_range(1, 100, Decimal(1)/7))  # log10 seems best

Для этих диапазонов, кажется, нет большой разницы между Decimal методами ln и log10, и оба, как правило, работают намного лучше, чем math.log2 или Decimal(x).ln / Decimal(2).ln.

0 голосов
/ 30 января 2020

Когда вы вычисляете логарифм числа, вы обычно получите иррациональный результат, если число не является степенью основания логарифма. Иррациональные числа не могут быть представлены точно в десятичной (или любой другой базе), поэтому вы получите приближение. И по мере того, как вы выполняете больше вычислений, ошибки распространяются.

Я не думаю, что есть какой-либо способ узнать, какой из двух результатов в последнем тесте является более точным. Они оба одинаковы в первых 16 разрядах, что является точностью с плавающей запятой двойной точности. Даже если вы используете библиотеку decimal, она может использовать внутреннее число с плавающей запятой для вычисления трансцендентных функций. Я подозреваю, что они отличаются только в последних 1-2 битах двоичного результата, поэтому они действительно близки. Но ошибки могут увеличиваться при выполнении большего количества расчетов с результатами.

Если вам нужна точность, избегайте использования трансцендентных функций.

См. Также Не нарушена ли математика с плавающей запятой?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...