gegmopo4: (Default)
[personal profile] gegmopo4

Задачка для младших инженеров-программистов электронно-вычислительных машин.

C:

#include <math.h>
#include <stdio.h>
int main()
{
    printf("%d\n", (pow(43, 10) == 21611482313284249ll));
    return 0;
}

Python:

import math
print(math.pow(43, 10) == 21611482313284249)

Вопрос: что выведется и почему?

Date: 2012-07-29 12:59 am (UTC)
From: [identity profile] salas.livejournal.com
Питон не знаю, но очевидно, что pow одинаковый, а отличается дальнейшее обращение с его значением. На мой вкус, оно одинаково неправильное, потому что при применении ==/!= к floating point нужно по умолчанию выдавать хотя бы предупреждение, а уж приводить при этом тип налево или направо — дело десятое.

С другой стороны, на перле 43**10 вычисляется точно. И таки кто из них горбатый?
Upd: инструкцию и здесь надо читать, особенно редко применяемые места. Если не вспоминать про bignum и т.п. — то горб вполне есть, просто он на ещё больших числах. Что вполне в духе, да.
Edited Date: 2012-07-29 02:00 am (UTC)

Date: 2012-07-29 07:10 am (UTC)
ext_605364: geg MOPO4 (geg_MOPO4)
From: [identity profile] gegmopo4.livejournal.com
Да, именно так всё и есть. См. «Incredible issue in math.pow».

В Питоне 43**10 тоже вычисляется точно. И даже 43**100.

Date: 2012-07-29 06:21 am (UTC)
From: [identity profile] qkowlew.livejournal.com
Когда-то давным давно начальный этап обучения программированию непременно содержал описание битового представления чисел, ограничений арифметики "в цифре" и т.п.

А тут даже константу написать - надо как минимум лезть в мануал по каждому из языков.
И сравнивать плавающие операцией == - ну вааащщщщщще.

В моей личной практике была отладка кода, в котором накапливающаяся ошибка округления в тупо написанном алгоритме с double float давала в сочетании с вычитанием больших чисел эффект "0=1" на всего лишь сотне поступивших в программу результатов измерения.

Date: 2012-07-29 06:53 am (UTC)
From: [identity profile] http://users.livejournal.com/_winnie/
> И сравнивать плавающие операцией == - ну вааащщщщщще.
Пишущие на JavaScript, AWK, Lua, ... только так и сравнивают :)

Сравнивать с точностью до MY_EPSION?.. Сорри, что бы сравнить 43**10 и math.pow(43, 10) EPSILON должен быть не меньше чем 1.0 :)
Edited Date: 2012-07-29 02:05 pm (UTC)

Date: 2012-07-29 07:19 am (UTC)
ext_605364: geg MOPO4 (geg_MOPO4)
From: [identity profile] gegmopo4.livejournal.com
ll уже я добавил, иначе на 32-битных платформах терялась соль шутки.

У этой истории есть и мораль — не используйте плавучку в криптографии.

Date: 2012-07-29 09:00 am (UTC)
From: [identity profile] slobin.livejournal.com
Что добавляет конфузии из-за типографской путаницы "l" и "1". Особенно если не помнить твёрдо о существовании констант long long (кстати, а они в стандарте есть? не помню...).

... Sing, Maglor the Stranger, a ballade for me ...

Date: 2012-07-29 10:36 am (UTC)
ext_605364: geg MOPO4 (geg_MOPO4)
From: [identity profile] gegmopo4.livejournal.com
Есть, но возможно факультативно. На (всех?) популярных платформах есть и не меньше 64 бит.

Date: 2012-07-29 08:57 am (UTC)
From: [identity profile] slobin.livejournal.com
Ну, допустим, pow и прочие magic powers здесь вообще ни при чём. А что питон сравнивает длинные и плавающие НЕ приведением первых ко вторым -- я не знал. Но, в общем, логично -- так оно (сравнение) хотя бы транзитивно. Кстати, нашёл хороший запоминающийся пример:

>>> 1000000000000000000 == 1000000000000000000 + 0.0
True
>>> 1000000000000000001 == 1000000000000000001 + 0.0
False
>>> 1000000000000000002 == 1000000000000000002 + 0.0
False
>>> 1000000000000000003 == 1000000000000000003 + 0.0
False


Как вы думаете, когда будет следующий True? :-)

... В двадцать первом веке, в самом начале ...

Edited Date: 2012-07-29 08:58 am (UTC)

Date: 2012-07-29 09:08 am (UTC)
From: [identity profile] slobin.livejournal.com
Вдогонку:

>>> N = 1000000000000000000
>>> [x for x in xrange(N, N + 1000) if x == float(x)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: long int too large to convert to int

И они это называют языком высокого уровня? Срочно линяем отсюда куда-нибудь!

1> N = 1000000000000000000.
1000000000000000000
2> [X || X <- lists:seq(N, N + 1000), X == float(X)].
[1000000000000000000,1000000000000000128,
1000000000000000256,1000000000000000384,1000000000000000512,
1000000000000000640,1000000000000000768,1000000000000000896]

Ага, сравнение длинных с плавающими в эрланге и питоне устроено одинаково. :-)

... Целуются обычно так - берётся девушка красивая ...

Date: 2012-07-29 10:39 am (UTC)
ext_605364: geg MOPO4 (geg_MOPO4)
From: [identity profile] gegmopo4.livejournal.com
Это неправильный Питон, и у него неправильный xrange. В правильном Питоне:
>>> N = 1000000000000000000
>>> [x for x in range(N, N + 1000) if x == float(x)]
[1000000000000000000, 1000000000000000128, 1000000000000000256, 1000000000000000384, 1000000000000000512, 1000000000000000640, 1000000000000000768, 1000000000000000896]

Date: 2012-07-29 10:48 am (UTC)
ext_605364: geg MOPO4 (geg_MOPO4)
From: [identity profile] gegmopo4.livejournal.com
Комментарии к реализации сравнения чисел с плавающей точкой:

Comparison is pretty much a nightmare. When comparing float to float, we do it as straightforwardly (and long-windedly) as conceivable, so that, e.g., Python x == y delivers the same result as the platform C x == y when x and/or y is a NaN.

When mixing float with an integer type, there's no good uniform approach. Converting the double to an integer obviously doesn't work, since we may lose info from fractional bits. Converting the integer to a double also has two failure modes: (1) a long int may trigger overflow (too large to fit in the dynamic range of a C double); (2) even a C long may have more bits than fit in a C double (e.g., on a a 64-bit box long may have 63 bits of precision, but a C double probably has only 53), and then we can falsely claim equality when low-order integer bits are lost by coercion to double. So this part is painful too.

Edited Date: 2012-07-29 10:50 am (UTC)

Date: 2012-07-29 02:05 pm (UTC)
From: [identity profile] http://users.livejournal.com/_winnie/
Меня сейчас добило ещё вот это:

>>> print pow(43, 10) == 43**10
True
>>> from math import pow
>>> pow(43, 10) == 43**10
False
Edited Date: 2012-07-29 02:06 pm (UTC)

Date: 2013-09-11 03:57 pm (UTC)
From: [identity profile] molostoff.livejournal.com
а я не взирая на pow посмотрел на printf (где собстно %d)

таким образом в первой строке вывод будет 0 или 1, а во второй True или False

про формат чисел LL мне неизвестно. С требует явного указания типа здесь, т.к. оригинальный С long long int не имеет.

Date: 2013-09-11 05:59 pm (UTC)
ext_605364: geg MOPO4 (geg_MOPO4)
From: [identity profile] gegmopo4.livejournal.com
long long int есть в C со стандарта 1999-го года.

Date: 2013-09-11 06:21 pm (UTC)
From: [identity profile] molostoff.livejournal.com
(блин, дубль джва)

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

про ll я не помню. увы. что-то из виндовс. точнее в с99 не надо ll : 6.4.4.1 (http://www.open-std.org/jtc1/sc22/wg14/www/docs/C99RationaleV5.10.pdf)Unsuffixed integer constants may have different types in C99 than in C89. Such
10 constants greater than LONG_MAX are of type unsigned long in C89, but are of
type long long in C99 (if long long has more range than long).
тоесть implicitly.

про явное указание типа: оно должно быть указано везде в вышеприведенном C, в частности %d заберет со стека int, в то время как FALSE или TRUE могут быть определены как 0L и 1L (литры наверно?)

а питон печатает boolean.

вопрос с вычислениями (pow) в части C целиком зависит от реализации компилятора, в частности есть ли в BSP операции c longlong int (== например), какие они, как их использует компилятор при компиляции (а ведь может) и тп. то есть на него нету ответа. по кр мере стандарт языка здесь не помжет.
Edited Date: 2013-09-11 06:57 pm (UTC)

Date: 2013-10-03 05:45 pm (UTC)
ext_605364: geg MOPO4 (geg_MOPO4)
From: [identity profile] gegmopo4.livejournal.com
Клятый ЖЖ спрятал комментарий — в почте вижу, а в посте нет. Только через ЖЖ-шный инбокс удалось достать.

> вы путаете стандарт языка и реализацию компилятора.

Обычно компиляторы стараются реализовать стандарт. Отклонения считаются багами (или фичами).

> вто время как вопрос был о том что выведется, а не как должно быть написано.

Да, разумеется, результат платформозависим. Поэтому требовалось подумать, почему получен такой ответ. Угадать-то его с 50% вероятностью дело нехитрое.

> точнее в с99 не надо ll : 6.4.4.1

Вот этого я не знал. Да, это хорошо, это правильно.

> FALSE или TRUE могут быть определены как 0L и 1L

При чём здесь какие-то FALSE и TRUE? Они даже не упоминаются в коде.

> вопрос с вычислениями (pow) в части C целиком зависит от реализации компилятора

Да, это платформозависимый вопрос. Ответ на него зависит от числа разрядов мантиссы в double. Но практически на всех используемых сейчас платформах он однозначен.

Date: 2013-10-03 08:45 pm (UTC)
From: [identity profile] molostoff.livejournal.com
"Отклонения считаются багами (или фичами)." Дану, народ, который собирает компилятор под какой -либо процессор не особо этим заморачивается, т.к. одни части собираются другими частями (т.н. bootstrap compiler), и до сертификации на соответствие стандарту если и дойдет, то уже тогда, когда процессор устареет морально.

да. ну так вот - предположим, питон собирается на той же платформе с той же libm (math) то есть берет ту же pow из C. поэтому если оба этих два примера на одной и той же платформе в части pow вернут одно и то же (почти, см. тут (http://stackoverflow.com/a/5246964/933849)), то нас может волновать только как работает в них сравнение '==' в отношении длинных лонгов на этой платформе... ну и далее в том же духе. то есть при всех спокойных (обычных) обстоятельствах результат вычисления стремится быть одинаков для этих двух примеров.

ну и разумаеется печатать они будут разные байты - питон свой буул а С напечатает int.

"При чём здесь какие-то FALSE и TRUE? Они даже не упоминаются в коде."
а при том, что это результат операции сравнения '==', в данном случае с константой.

Profile

gegmopo4: (Default)
gegmopo4

May 2015

S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930
31      

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jun. 23rd, 2017 03:34 pm
Powered by Dreamwidth Studios