Добавить в корзинуПозвонить
Найти в Дзене

Trunc и Round в Lazarus: в чем разница и когда что использовать

При разработке приложений в среде Lazarus (Free Pascal) часто возникает необходимость преобразования вещественных чисел в целые. Две основные функции для этого — Trunc и Round. На первый взгляд они похожи, но между ними есть принципиальные различия, которые могут привести к неожиданным ошибкам, если не понимать их поведения. Функция Trunc отбрасывает дробную часть числа, возвращая целое значение, которое находится ближе к нулю. var x: Double; begin x := 3.14; ShowMessage(IntToStr(Trunc(x))); // Результат: 3 x := -3.14; ShowMessage(IntToStr(Trunc(x))); // Результат: -3 end; Ключевая особенность: Trunc всегда округляет в сторону нуля. Функция Round возвращает ближайшее целое число в соответствии с правилами математического округления. В Lazarus (Free Pascal) по умолчанию используется «банковское округление» (round to even), когда число находится ровно посередине. var x: Double; begin x := 3.14; ShowMessage(IntToStr(Round(x))); // Результат: 3 x := 3.5; ShowMessage(IntToStr(Round(x))); //
Оглавление

При разработке приложений в среде Lazarus (Free Pascal) часто возникает необходимость преобразования вещественных чисел в целые. Две основные функции для этого — Trunc и Round. На первый взгляд они похожи, но между ними есть принципиальные различия, которые могут привести к неожиданным ошибкам, если не понимать их поведения.

Основные отличия

Trunc — простое отбрасывание дробной части

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

var x: Double;
begin
x := 3.14;
ShowMessage(IntToStr(Trunc(x))); // Результат: 3
x := -3.14;
ShowMessage(IntToStr(Trunc(x))); // Результат: -3
end;

Ключевая особенность: Trunc всегда округляет в сторону нуля.

Round — математическое округление

Функция Round возвращает ближайшее целое число в соответствии с правилами математического округления. В Lazarus (Free Pascal) по умолчанию используется «банковское округление» (round to even), когда число находится ровно посередине.

var x: Double;
begin
x := 3.14;
ShowMessage(IntToStr(Round(x))); // Результат: 3
x := 3.5;
ShowMessage(IntToStr(Round(x))); // Результат: 4 (или 4 при банковском округлении?)
x := 4.5;
ShowMessage(IntToStr(Round(x))); // Результат: 4 (банковское округление!)
end;

Важное предупреждение: В Free Pascal по умолчанию действует банковское округление (round to even). Это означает, что 3.5 округлится до 4, а 4.5 — тоже до 4 (ближайшее чётное). Это отличается от привычного арифметического округления, принятого во многих других языках.

Сравнительная таблица

Когда лучше применять Trunc?

1. Работа с пикселями и графикой

При работе с координатами на экране или в графических элементах отбрасывание дробной части часто предпочтительнее.

// Координаты пикселей не могут быть дробными
Canvas.MoveTo(Trunc(StartX), Trunc(StartY));
Canvas.LineTo(Trunc(EndX), Trunc(EndY));

2. Преобразование мер длины при округлении вниз

Например, при переводе метров в сантиметры с отбрасыванием лишнего.

function MetersToCm(Meters: Double): Integer;
begin
Result := Trunc(Meters * 100); // Просто отбрасываем лишние миллиметры
end;

3. Выделение целой части числа

Когда нужно получить именно целую часть, а не округлённое значение.

var
Value: Double;
IntPart, FracPart: Integer;
begin
Value := 123.456;
IntPart := Trunc(Value); // 123
FracPart := Trunc(Frac(Value) * 1000); // 456
end;

4. Гарантированное округление вниз (к нулю)

Если логика программы требует именно такого поведения.

Когда лучше применять Round?

1. Финансовые и бухгалтерские расчёты

При работе с деньгами требуется математически корректное округление до копеек.

function RoundToKopecks(Amount: Double): Integer;
begin
// Округляем до ближайшей копейки
Result := Round(Amount * 100);
end;

Внимание: Для серьёзных финансовых расчётов лучше использовать специализированные типы (Currency) или явно задавать режим округления через SetRoundMode.

2. Отображение значений пользователю

Когда нужно показать результат, ожидаемый человеком.

// Средний балл ученика
AverageScore := Round(TotalScore / SubjectCount);
LabelAverage.Caption := 'Средний балл: ' + IntToStr(AverageScore);

3. Преобразование при потере точности

Если важно минимизировать ошибку округления.

4. Статистические расчёты

Где требуется стандартное математическое округление.

Особые случаи и подводные камни

Переполнение

Обе функции могут вызвать исключение при переполнении, если результат не помещается в Integer или Int64. В Lazarus по умолчанию это отслеживается на этапе компиляции.

var
BigValue: Double;
begin
BigValue := 1e20; // Очень большое число
// Trunc(BigValue); // Ошибка переполнения!
// Round(BigValue); // Ошибка переполнения!
end;

Выход за границы Integer

Free Pascal имеет диапазон Integer -2147483648..2147483647. При работе с очень большими числами используйте Trunc/Round с типом Int64.

var
LargeDouble: Double;
LargeInt: Int64;
begin
LargeDouble := 5e12;
LargeInt := Trunc(LargeDouble); // всё в порядке, используем Int64
end;

Изменение режима округления Round

При необходимости можно изменить поведение Round:

uses
Math;
// Установка арифметического округления (от 0.5 вверх)
SetRoundMode(rmUp);
Value := Round(2.5); // Результат: 3
// Возврат к банковскому округлению
SetRoundMode(rmNearest);
Value := Round(2.5); // Результат: 2 (банковское)

Здесь надо сказать, что SetRoundMode работает своеобразно, и результат может быть неожиданным. Не советуют использовать эту функцию. Возможно, я расскажу об этом когда-нибудь подробнее.

Практические советы

-2

Заключение

Выбор между Trunc и Round зависит от конкретной задачи:

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

Помните о банковском округлении в Free Pascal по умолчанию! Если вам нужно классическое арифметическое округление (0.5 всегда вверх), используйте SetRoundMode(rmUp) или реализуйте собственное округление через Floor/Ceil с проверкой дробной части.

Правильный выбор функции округления — залог точности и предсказуемости ваших программ на Lazarus (ну и не только на Lazarus, конечно).

На этом всё. Подписывайтесь на канал, чтобы ничего не пропустить.