Просто для удовольствия я играл с представлением поплавков, следуя определениям из стандарта C99, и я написал код ниже.
Код печатает двоичное представление поплавков в 3 отдельных группах
SIGN EXPONENT FRACTION
, и после этого он печатает сумму, которая при суммировании с достаточной точностью покажет значение, которое действительно существует в аппаратном обеспечении.
Поэтому, когда вы пишете float x = 999...
компилятор преобразует это число в битовое представление, напечатанное функцией xx
, так что сумма, напечатанная функцией yy
, будет равна заданному числу.
В действительности эта сумма является только приближение. Для числа 999,999,999 компилятор будет вставлять в бит представление float число 1,000,000,000
После кода я присоединяю консольный сеанс, в котором я вычисляю сумму терминов для обеих констант (минус PI и 999999999) который действительно существует в аппаратном обеспечении, вставленном там компилятором.
#include <stdio.h>
#include <limits.h>
void
xx(float *x)
{
unsigned char i = sizeof(*x)*CHAR_BIT-1;
do {
switch (i) {
case 31:
printf("sign:");
break;
case 30:
printf("exponent:");
break;
case 23:
printf("fraction:");
break;
}
char b=(*(unsigned long long*)x&((unsigned long long)1<<i))!=0;
printf("%d ", b);
} while (i--);
printf("\n");
}
void
yy(float a)
{
int sign=!(*(unsigned long long*)&a&((unsigned long long)1<<31));
int fraction = ((1<<23)-1)&(*(int*)&a);
int exponent = (255&((*(int*)&a)>>23))-127;
printf(sign?"positive" " ( 1+":"negative" " ( 1+");
unsigned int i = 1<<22;
unsigned int j = 1;
do {
char b=(fraction&i)!=0;
b&&(printf("1/(%d) %c", 1<<j, (fraction&(i-1))?'+':')' ), 0);
} while (j++, i>>=1);
printf("*2^%d", exponent);
printf("\n");
}
void
main()
{
float x=-3.14;
float y=999999999;
printf("%lu\n", sizeof(x));
xx(&x);
xx(&y);
yy(x);
yy(y);
}
Вот сеанс консоли, в котором я вычисляю реальное значение float, которое существует в аппаратном обеспечении. Я использовал bc
для печати суммы терминов, выводимых основной программой. Можно вставить эту сумму в python repl
или что-то подобное.
-- .../terra1/stub
@ qemacs f.c
-- .../terra1/stub
@ gcc f.c
-- .../terra1/stub
@ ./a.out
sign:1 exponent:1 0 0 0 0 0 0 fraction:0 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 0 1 1
sign:0 exponent:1 0 0 1 1 1 0 fraction:0 1 1 0 1 1 1 0 0 1 1 0 1 0 1 1 0 0 1 0 1 0 0 0
negative ( 1+1/(2) +1/(16) +1/(256) +1/(512) +1/(1024) +1/(2048) +1/(8192) +1/(32768) +1/(65536) +1/(131072) +1/(4194304) +1/(8388608) )*2^1
positive ( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
-- .../terra1/stub
@ bc
scale=15
( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
999999999.999999446351872
Вот и все. Фактически значение 999999999
999999999.999999446351872
Вы также можете проверить с помощью bc
, что -3.14 также возмущено. Не забудьте установить коэффициент scale
в bc
.
Отображаемая сумма - это то, что внутри аппаратного обеспечения. Значение, которое вы получаете, вычисляя его, зависит от установленного вами масштаба. Я установил коэффициент scale
равным 15. Математически, с бесконечной точностью, кажется, что это 1 000 000 000.
Вы можете это сделать полностью, это просто проблема с порядком:
[ unicode(x.strip()) if x is not None else '' for x in row ]
Обратите внимание, что это фактически использует другую конструкцию языка, условное выражение , которое само по себе не является часть синтаксиса понимания , в то время как if
после for…in
является частью понятий списка и используется для filter элементов из исходной итерации.
Условные выражения могут использоваться во всех ситуациях, когда вы хотите выбрать между двумя значениями выражения на основе некоторого условия. Это делает то же, что и трёхмерный оператор ?:
, который существует на других языках . Например:
value = 123
print(value, 'is', 'even' if value % 2 == 0 else 'odd')
Один из способов:
def change(f):
if f is None:
return unicode(f.strip())
else:
return ''
row = [change(x) for x in row]
Хотя тогда у вас есть:
row = map(change, row)
Или вы можете использовать встроенный lambda.
Вот еще один иллюстративный пример:
>>> print(", ".join(["ha" if i else "Ha" for i in range(3)]) + "!")
Ha, ha, ha!
Он использует тот факт, что if i
оценивает False
для 0
и True
для всех других значений, генерируемых функцией range()
. Поэтому понимание списка оценивается следующим образом:
>>> ["ha" if i else "Ha" for i in range(3)]
['Ha', 'ha', 'ha']
Другие решения отлично подходят для одной конструкции if
/ else
. Тем не менее, трехмерные выражения в понимании списка, возможно, трудно читать.
Использование функции облегчает читаемость, но такое решение трудно расширить или адаптировать в рабочем процессе, где отображение является входом. Словарь может облегчить эти проблемы:
row = [None, 'This', 'is', 'a', 'filler', 'test', 'string', None]
d = {None: '', 'filler': 'manipulated'}
res = [d.get(x, x) for x in row]
print(res)
['', 'This', 'is', 'a', 'manipulated', 'test', 'string', '']
Конкретная проблема уже решена в предыдущих ответах, поэтому я обращусь к общей идее использования условностей внутри понятий списка.
Вот пример, показывающий, как условные обозначения могут быть записаны внутри понимания списка :
X = [1.5, 2.3, 4.4, 5.4, 'n', 1.5, 5.1, 'a'] # Original list
# Extract non-strings from X to new list
X_non_str = [el for el in X if not isinstance(el, str)] # When using only 'if', put 'for' in the beginning
# Change all strings in X to 'b', preserve everything else as is
X_str_changed = ['b' if isinstance(el, str) else el for el in X] # When using 'if' and 'else', put 'for' in the end
Обратите внимание, что в первом понимании списка для X_non_str
порядок:
значение для выражения 1 , если expression2
blockquote>и в последнем понимании списка для
X_str_changed
порядок:value1 , если expression1 else значение2 для expression2
blockquote>Мне всегда трудно помнить, что значение 1 должно быть раньше, если и значение2 должно быть после. Моя голова хочет, чтобы оба были либо до, либо после.
Я предполагаю, что он создан так, потому что он похож на обычный язык, например. «Я хочу остаться внутри, если идет дождь, иначе я хочу выйти на улицу»