Int main(void)
{
const double CROP = 2E16; // мировой урожай пшеницы в зернах
double current, total;
int count = 1;
printf("квадрат добавлено итого");
printf("процент от \n");
printf(" зерен зерен");
printf("мирового урожая\n");
total = current = 1.0; /* начинаем с одного зернышка*/
printf("%4d %13.2e %12.2e %12.2e\n", count, current,
total, total/CROP);
while (count < SQUARES)
{
count = count + 1;
current = 2.0 * current;
/* удвоить количество зерен на следующей клетке*/
total = total + current; /* обновить итоговую сумму*/
printf("%4d %13.2e %12.2e %12.2e\n", count, current,
total, total/CROP);
}
printf("Вот и все.\n");
return 0;
}
Сначала выходные данные не должны были вызывать у правителя беспокойство:
На десяти клетках мудрец получил чуть больше тысячи зерен пшеницы, но взгляните на результат для 55 клетки:
55 1.80е+16 3.60е+16 1.80е+00
Плата мудреца превысила весь мировой урожай! Если хотите выяснить, что произойдет к 64-й клетке, выполните программу самостоятельно.
Приведенный пример иллюстрирует феномен экспоненциального роста. Население мира и расходование энергетических ресурсов растет по тому же закону.
Операция деления: /
В языке С символ / используется для обозначения деления. Значение, находящееся слева от символа /, делится на значение, указанное справа. Например, следующий оператор присваивает переменной four значение 4.0:
four = 12.0/3.0;
Деление работает по-разному для целочисленных типов и типов с плавающей запятой. В результате деления с плавающей запятой получается число с плавающей запятой, а целочисленное деление дает целое число. Так как целое число не может иметь дробной части, деление 5 на 3 не является точным, поскольку результат не содержит дробной части. В языке С любая дробная часть, полученная при делении двух целых чисел, отбрасывается. Этот процесс называется усечением.
Запустите программу, показанную в листинге 5.6, чтобы посмотреть, как работает усечение, и узнать, чем отличается деление целых чисел от деления чисел с плавающей запятой.
Листинг 5.6. Программа divide.с
/* divide.c -- деление, каким мы его знаем*/
#include <stdio.h>
Int main(void)
{
printf("Целочисленное деление: 5/4 is %d \n", 5/4);
printf("Целочисленное деление: 6/3 is %d \n", 6/3);
printf("Целочисленное деление: 7/4 is %d \n", 7/4);
printf("Деление с плавающей запятой: 7./4. is %1.2f \n", 7./4.);
printf("Смешанное деление: 7./4 is %1.2f \n", 7./4);
return 0;
}
В листинге 5.6 представлен случай “смешанных типов”, когда значение с плавающей запятой делится на целое число. По сравнению с рядом других языков С более либерален и разрешает выполнять такие операции, однако обычно вы должны избегать смешивания типов. Ниже приведены результаты выполнения программы:
Целочисленное деление: 5/4 равно 1 Целочисленное деление: 6/3 равно 2 Целочисленное деление: 7/4 равно 1 Деление с плавающей запятой: 7./4. равно 1.75 Смешанное деление: 7./4 равно 1.7 5
Обратите внимание, что целочисленное деление не округляет до ближайшего целого, а всегда выполняет усечение (т.е. отбрасывает дробную часть). При смешивании водной операции целых чисел и чисел с плавающей запятой ответ оказывается таким же, как и в случае деления чисел с плавающей запятой. На самом деле компьютер не способен делить число с плавающей запятой на целое число, и поэтому компилятор преобразует оба операнда к одному типу. В данном случае перед выполнением деления целое число преобразуется в число с плавающей запятой.
Приоритеты операций
Рассмотрим следующую строку кода:
butter =25.0+60.0*n/ SCALE;
В этом операторе присутствуют операции сложения, умножения и деления. Какая из них выполнится первой? Будет ли 25.0 суммироваться с 60.0, полученный результат 85.0 умножаться на n, после чего произведение делиться на SCALE? Или же 60.0 умножится на n, к полученному произведению прибавится 2 5.0, после чего результат сложения разделится на SCALE? А, может быть, будет использоваться вообще другой порядок выполнения операции? Предположим, что n равно 6. 0, a SCALE 2.0. При таких значениях первый подход даст результат 255, а второй — 192.5. По всей видимости, в программе на С задействован другой порядок, поскольку переменная butter в итоге получает значение 205.0.
Очевидно, что порядок выполнения различных операций оказывает влияние на конечный результат, следовательно, язык С нуждается в однозначных правилах выбора того, что должно выполняться в первую очередь. Эта проблема решается путем установки порядка выбора операций. Каждой операции назначается уровень приоритета. Как и в обычной арифметике, умножение и деление имеют более высокий приоритет, чем сложение и вычитание, поэтому они выполняются первыми. А что, если две операции обладают одинаковыми приоритетами? Когда они применяются к одному и тому же операнду, то выполняются в порядке следования внутри оператора. Большинство операций выполняются слева направо. (Операция = является исключением из этого правила.) Поэтому в операторе
butter =25.0+ 60.0 *n/ SCALE; операции выполняются в следующем порядке:
60.0 * n
Сначала выполняется первая операция * или / в выражении (при условии, что n равно 6, 60.0 * n дает 360.0).
360.0 / SCALE
Затем выполняется вторая операция * или / в выражении.
25.0 + 180
В завершение (поскольку SCALE равно 2.0) выполняется первая операция + в выражении, давая результат 205.0.
А что, если нужно обеспечить выполнение операции сложения раньше операции деления? Тогда можно поступить так, как это сделано в следующем операторе:
flour = (25.0 + 60.0 * n) / SCALE;
Все, что заключено в круглые скобки, выполняется первым. Внутри круглых скобок действуют обычные правила. В приведенном примере сначала выполняется умножение, а затем сложение. На этом вычисление выражения в круглых скобках завершено. Затем результат может быть разделен на SCALE.
Некоторые дополнительные операции
В языке С имеется около 40 операций, и некоторые из них применяются гораздо чаще других. Те, с которыми вы уже ознакомились, относятся к наиболее распространенным операциям, но к этому списку можно добавить еще четыре очень полезных операции.
Операция sizeof и тип size_t
Операция sizeof возвращает размер своего операнда в байтах. (Вспомните также, что байт в языке С определен как размер, используемый для типа char. В прошлом байт чаще всего состоял из 8 битов, но некоторые наборы символов использовали байты большего размера.) Операндом может быть конкретный объект данных, такой как имя переменной, либо им может быть тип. Если это тип, скажем, float, то операнд должен быть помещен в круглые скобки. В примере, представленном в листинге 5.8, показаны обе формы операндов.
Листинг 5.8. Программа sizeof.с
// sizeof.c -- использование операции sizeof
// в примере применяется определенный в стандарте с99 модификатор %z
#include <stdio.h>
