Что такое "Советы по Delphi"?
«Советы по Delphi» — коллекция ответов на нетрадиционные вопросы программирования на Delphi, нестандартных решений, хитростей и интересных идей. Для практической пользы дела приведены конкретные примеры кода, позволяющие донести идею или полностью ответить на заданный вопрос.
Автором предусматривается попытка на периодичность издания, подписаться на уведомления о выходе новых версий можно здесь. При составлении «Советов» не ставилась цель включить ВСЕ материалы, отбирались лишь самые интересные. Источником «Советов» служили многочисленные западные источники (FAQ), кропотливо отобранные и переведенные на русский язык.
Учитывая плачевное состояние наших линий, «Советы» практически не содержат графики. Весь приведенный код отформатирован таким образом, чтобы вы могли скопировать его прямо со странички в свое приложение. По этой же причине отсутствует online-версия «Советов».
Так, если Вы обладаете интересной информацией, и ее нет в «Советах», не поленитесь, пришлите ее мне. Пожалуйста не задавайте мне вопросов по электронной почте. У меня есть работа и я занятый человек. Помещайте свои вопросы в группу новостей, я попытаюсь ответить на них там.
Шлите примеры, советы, полезности, статьи и давайте ссылки на свои и не свои сайты. От вас самих зависит наполняемость советов. Авторы! Дайте вторую жизнь вашим произведениям! Присылайте статьи и переводы!
Не удивляйтесь, если в «Советах» Вы обнаружите код для Delphi1 или даже для TurboPascal'я. Сам Паскаль практически не изменился, а идеи, реализация и технология живы до сих пор. Для описания какой-либо функции можно заглянуть в электронную справку, а для поиска идеи — в «Советы».
Предупреждение
Я не отвечаю за последствия применения приведенного кода. Используйте его на свой страх и риск. Не нужно меня обвинять и слать гневные письма, если Ваш компьютер взорвется из-за какого-нибудь «Совета».
Тем не менее, если Ваш компьютер все-таки взорвался, сообщите мне пожалуйста об этом и я просмотрю код в поисках ошибки.
Преобразование дробной и целой части REAL-числа в два целых
Я написал программу, которая делает это. Это DOS-программа. Вы вызываете ее с десятичным числом, передаваемым в качестве параметра. После чего программка выведет 3 колонки, в первой будет находиться исходное число, две остальные будут содержать числитель и знаменатель. Вы можете преобразовать программу в функцию и применять ее в своих приложениях, но, думаю, это несложно, и с этим вы справитесь сами.
Для ее запуска достаточно в подсказке DOS набрать ее имя и число:
CONTFRAC 3.141592654
program contfrac; { непрерывные дроби }
{$N+}
const
order = 20;
var
y, lasterr, error, x: extended;
a: array [0..order] of longint;
i, j, n: integer;
op, p, q: longint;
begin
lasterr := 1e30;
val(paramstr(1), y, n);
if n <> 0 then halt;
x := y;
a[0] := trunc(x);
writeln;
writeln(a[0]:20, a[0]:14, 1:14);
{ это может вызвать резкую головную боль и галлюцинации }
for i := 1 to order do begin
x := 1.0 / frac(x);
a[i] := trunc(x);
p := 1;
q := a[i];
for j := pred(i) downto 0 do begin
op := p;
p := q;
q := a[j] * q + op;
end;
error := abs(y – int(q) / int(p));
if abs(error) >= abs(lasterr) then halt;
writeln(a[i]:20, q:14, p:14, error:10);
if error < 1e-18 then halt;
lasterr := error;
end;
end.
Теперь попытаюсь объяснить мой алгоритм (он, по-моему, достаточно быстрый). Вот схема:
Допустим, мы используем число 23.56.
Берем наше натуральное число и производим целочисленное деление на 1.
23.56 div 1 = 23
Теперь вычитаем результат из числа, с которого мы начали.
23.56 – 23 = .56
Для преобразования значения в целое мы просто умножаем его на 100, и, при необходимости, приводим его к целому.
valA := (val div 100);
valB := (valA – val);
or
valB := (valA – val) * 100;
val = 23.56
ValA = 23
ValB = .56 or 56
Есть ли функция, выполняющая пpеобpазование пеpеменной real в integer?
Nomadic советует:
Hа самом деле есть две функции — Round и Trunc (округление и отсечение дробной части соответственно).
Кстати, функции эти были уже в самых ранних версиях Паскаля. Так что мой совет — изучите Паскаль — полезно.
Hy, если yж дело идет к изyчению списка фyнкций :), то yпомянy еще Ceil и Floor. Unit Math;
Кстати, втоpая из них мне очень пpигодилась для полyчения экспоненты числа. Имеется в видy экспонента: X=1E 13 [001193]
Почему непpавильно pаботает функция StrToFloat?
Nomadic советует:
Пишу даже прямо StrToFloat('32.34'), к примеру, получаю исключение «'32.34' is not valid float». Если пишу число без десятичной точки, то все ОК. А какой у тебя DecimalSeparator? В Russian settings почему-то по умолчанию считается, что разделитеь дроби – запятая. Пеpеустанови пpи запуске пpогpаммы
DecimalSeparator := '.';
Или пользуйся этой функцией так:
StrToFloat('32,24');
Сергей AKA WildSery прислал свой вариант:
Привожу мой вариант, написал для своего приложения за 20 минут. В силу специфики приложения не утруждал себя прописью полностью "рублей" и "копеек", а ограничился "руб." и "коп.", а также не было необходимости в знаке числа, по это все добавляется буквально 3-4 строками.
function currency2str (value: double): string;
const hundreds: array [0..9] of string = ('',' сто',' двести',' триста',' четыреста',' пятьсот',' шестьсот',' семьсот',' восемьсот',' девятьсот');
tens: array [0..9] of string = ('','',' двадцать',' тридцать',' сорок',' пятьдесят',' шестьдесят',' семьдесят',' восемьдесят',' девяносто');
ones: array [0..19] of string = ('','','',' три',' четыре',' пять',' шесть',' семь',' восемь',' девять',' десять',' одиннадцать',' двенадцать',' тринадцать',' четырнадцать',' пятнадцать',' шестнадцать',' семнадцать',' восемнадцать',' девятнадцать');
razryad: array [0..6] of string = ('',' тысяч',' миллион',' миллиард',' триллион',' квадриллион',' квинтиллион');
var s: string; i: integer; val: int64;
function shortnum(s: string; raz: integer): string;
begin
Result:=hundreds[StrToInt(s[1])];
if strtoint(s)=0 then exit;
if s[2]<>'1' then begin
Result:=Result+tens[StrToInt(s[2])];
case strtoint(s[3]) of
1: if raz=1 then result:=result+' одна' else result:=result+' один';
2: if raz=1 then result:=result+' две' else result:=result+' два';
else result:=result+ones[strtoint(s[3])];
end;
Result:=Result+razryad[raz];
case strtoint(s[3]) of
0,5,6,7,8,9: if raz>1 then result:=result+'ов';
1: if raz=1 then result:=result+'а';
2,3,4: if raz=1 then result:=result+'и' else if raz>1 then result:=result+'а';
end;
end else begin
Result:=Result+ones[StrToInt(Copy(s,2,2))];
Result:=Result+razryad[raz];
if raz>1 then result:=result+'ов';
end;
end;
begin
val:=Trunc(value);
if val=0 then begin result:='ноль'; exit; end;
s:=IntToStr(val); Result:=''; i:=0;
while length(s)>0 do begin
Result:=shortNum(Copy('00'+s,Length('00'+s)-2,3),i)+Result;
if length(s)>3 then s:=copy(s,1,length(s)-3) else s:='';
inc(i);
end;
s:=IntToStr(Trunc((value-val)*100+0.5));
Result:=Result+' руб. '+s+' коп.';
end;
Добавление даты и времени в компонент Memo
{ Следующий код вставляет значение даты/времени в memo-поле. }
Var
s : string;
begin
s := DateToStr( Date ) + ' ' + TimeToStr( Time ) + ' :';
Memo1.Lines.Insert(0, s);
Memo1.SetFocus;
Memo1.SelStart := Length(s);
Memo1.SelLength := 0;