Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Сокровищница
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  18:35[Войти] | [Зарегистрироваться]

Mathcad-подобная функция форматирования вещественных чисел.

Николай Чуносов
дата публикации 12-12-2006 07:55

Mathcad-подобная функция форматирования вещественных чисел.

При написании приложения для решения научных задач я столкнулся с проблемой, что предоставляемые Delphi функции преобразования вещественного числа в строку не устраивают меня по тем или иным причинам. В Matcad’е имеется стиль форматирования, который мне казался очень удобным и хотелось использовать подобное форматирование в своем приложении.

Стиль управляется тремя параметрами:
  • Число знаков после запятой - Digits
  • Флаг заполнения нулями недостющих знаков – ZeroFill (0.2 –> 0.200 при Digits = 3)
  • Экспонециальный порог – ExpThreshold. Если число по модулю больше 10^ExpThreshold или меньше 10^(–ExpThreshold), то оно представляется в экспоненциальном формате, иначе в формате с фиксированной запятой.

Рассмотрим всем известные стандартные функции форматирования вещественных чисел, и чем они не подходят для решения поставленной задачи.

FloatToStr
однозначно не подходит, т.к. не имеет вообще никаких управляющих параметров.

FormatFloat
поддерживает управляющую строку, может отображать число либо в фиксированном, либо в экспоненциальном виде, однако сама не решает в каком – не подходит.

FloatToStrF / FloatToText
Формат ffNumber
использует фиксированное представление и разделитель тысяч. Не помню случая, чтобы в научных программах или статьях использовался разделитель тысяч. Это больше для бухгалтерии.
Формат ffCurrency
тоже, что и ffNumber, но добавляет к строке символ валюты, руководствуясь настройками системной локали или структурой TFormatSettings.

Следующие два формата наиболее интересны для нашей цели:
ffExponent.
Параметр Precision функции FloatToStrF задает число цифр в мантиссе, одна в целой части, остальные в дробной. Лишние цифры входного значения отбрасываются, в этом случае последняя ставшаяся в дробной части цифра округляется. Параметр Digits задает число знаков в экспоненте. Допустимые значения 1 – 4, все остальные работают как 1. Если степень экспоненты положительная, то перед ней пишется знак "+". 0.00005 –> 5.00000E-005 (Precision = 6, Digits = 3) 123456789 –> 1.235E+8 (Precision = 4, Digits = 1)
ffFixed.
Параметр Digits задает число знаков после запятой. Недостающие знаки заполняются нулями. Параметр Precision задает число значащих цифр в результирующей строке. Если целая часть входного значения содержит больше цифр, чем задано в Precision, то значение форматируется в экспоненциальной форме (только, в отличие от ffExponent, почему-то не добавляется знак "+", если степень экспоненты положительная). 1234.56789 –> 1234,57 (Precision = 10, Digits = 2) 1234.56789 –> 1.23E03 (Precision = 3, Digits = 2) С одной стороны это работает подобно требуемому параметру ExpThreshold, но с другой стороны даже если входное значение содержит в дробной части Digits и более цифр, все равно в результирующую строку будет выведено не более Precision значащих цифр: 1234.56789 -> 1234.5700 (Precision = 6, Digits = 4)
ffGeneral.
С этим форматом функция выводит Precision значащих цифр, обрезания знаков после запятой не производится, “добивания” нулями до Digits- тожe не производится. Параметр Digits тут бесполезен, пока не используется экспоненциальный формат. Экспоненциальное представление применяется если входное значение меньше 0.00001, либо, как и в случае ffFixed, если целая часть содержит более Precision цифр.

Таким образом мы имеем формат, который умеет отображать значение в экспоненциальной форме - ffExponent, и формат, отображающий значение в фиксированной форме, с заданным числом знаков после запятой, и заполнением нулями недостающих знаков – ffFixed, если установить ему максимальное значение Precision (18 для типа Extended). А вот когда какой формат применять придется решать самостоятельно, анализируя входное значение.

Сделать это не сложно, стоит только взглянуть на код. Это будет проще всяких объяснений.

function FormatValue(Value: Extended; ExpTheshold, Digits: Byte; ZeroFill: Boolean): String;
var
  Min, Max: Extended;
  i, j: Integer;
begin
  if IsNaN(Value) then
  begin
    Result := 'NaN';
    Exit;
  end;

  if IsInfinite(Value) then
  begin
    if Sign(Value) = -1
      then Result := '-Inf'
      else Result := 'Inf';
    Exit;
  end;

  if Value = 0 then
  begin
    if ZeroFill
      then Result := FloatToStrF(Value, ffFixed, 18, Digits)
      else Result := FloatToStrF(Value, ffGeneral, 18, Digits);
    Exit;
  end;

  case ExpTheshold of
    0:   begin Max := 1e00; Min := 1e-00; end;
    1:   begin Max := 1e01; Min := 1e-01; end;
    2:   begin Max := 1e02; Min := 1e-02; end;
    3:   begin Max := 1e03; Min := 1e-03; end;
    4:   begin Max := 1e04; Min := 1e-04; end;
    5:   begin Max := 1e05; Min := 1e-05; end;
    6:   begin Max := 1e06; Min := 1e-06; end;
    7:   begin Max := 1e07; Min := 1e-07; end;
    8:   begin Max := 1e08; Min := 1e-08; end;
    9:   begin Max := 1e09; Min := 1e-09; end;
    10:  begin Max := 1e10; Min := 1e-10; end;
    11:  begin Max := 1e11; Min := 1e-11; end;
    12:  begin Max := 1e12; Min := 1e-12; end;
    13:  begin Max := 1e13; Min := 1e-13; end;
    14:  begin Max := 1e14; Min := 1e-14; end;
    15:  begin Max := 1e15; Min := 1e-15; end;
    16:  begin Max := 1e16; Min := 1e-16; end;
    17:  begin Max := 1e17; Min := 1e-17; end;
    else begin Max := 1e18; Min := 1e-18; end;
  end;

  if Value > 0 then
    if (Value < Min) or (Value > Max)
      then Result := FloatToStrF(Value, ffExponent, 1+Digits, 1)
      else Result := FloatToStrF(Value, ffFixed, 18, Digits)
  else
    if (Value > -Min) or (Value < -Max)
      then Result := FloatToStrF(Value, ffExponent, 1+Digits, 1)
      else Result := FloatToStrF(Value, ffFixed, 18, Digits);

  if not ZeroFill then
  begin
    i := Pos('E', Result)-1;
    //i := FastCharPos(Result, 'E')-1;
    if i = -1 then
    begin
      i := Length(Result);
      while i > 0 do
        if Result[i] in ['0',',','.'] then Dec(i)
        else begin
          SetLength(Result, i);
          Break;
        end;
    end
    else
    begin
      j := i;
      while j > 0 do
      begin
        if Result[j] in ['0',',','.'] then Dec(j)
        else begin
          Result := Copy(Result, 1, j) + Copy(Result, i+1, 256);
          Break;
        end;
      end;
    end;
  end;
end;

Итак, если число удовлетворяет условию 10^(–ExpThreshold) >= |Value| >= 10^ExpThreshold, то для его преобразования в строку используется формат ffFixed иначе ffExponent. Я использовал отдельное сравнение для положительного и отрицательного значения, т.к. мне не хотелось несколько раз вызывать функцию Abs.

Т.к. Precision при использовании экспоненциального формата задает общее число знаков в мантиссе и из них один всегда перед запятой, то нам нужно использовать Precision = Digits + 1.

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

Получилась несложная функция.


Смотрите также материалы по темам:
[Вещественные числа] [Форматы представления данных]

 Обсуждение материала [ 13-12-2006 14:43 ] 4 сообщения
  
Время на сайте: GMT минус 5 часов

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

Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

 
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.

Яндекс цитирования