Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2014.12.21;
Скачать: CL | DM;

Вниз

Упростить числосклонятор до полной нечитабельности   Найти похожие ветки 

 
MBo ©   (2014-05-20 22:13) [0]

Писал велосипедик для правильного склонения во множественном числе, в процессе думал об использовании открытого массива вместо трех строковых констант и избавления от case, но это чревато лишней проверкой его корректности, и не нашёл компактного выражения для вычисления индекса:

0 -> 0
1..3- > 1
4...13 -> 2

C масками и переводом в логические выражения и назад в арифметику получалось развесисто. Может, кому придёт в голову интересный вариант.
Сам полуобфусцированный велосипедик:

//usage: PluralWord(3, "рубль", "рубля", "рублей");
function PluralWord(Amount: Integer; const One, Two, Five: string): string;
begin
 Amount := Abs(Amount);
 case 4 * Ord(1 = (Amount mod 100) div 10) + (Amount - 1) mod 10 of
   0: Result := One;
   1..3: Result := Two;
   else
    Result := Five;
 end;
end;


 
antonn ©   (2014-05-20 22:24) [1]

я в вебе такое юзаю:
foo(30,array("пользователь", "пользователя", "пользователей"))

function foo($number, $titles){
   $cases = array (2, 0, 1, 1, 1, 2);
   return $titles[ ($number%100>4 && $number%100<20)? 2 : $cases[min($number%10, 5)] ];
}


 
MBo ©   (2014-05-20 22:39) [2]

Ага, несколько другая логика, но тоже довольно много внутри накручено, а тернарный оператор скрадывает объём выражения


 
Дмитрий СС   (2014-05-20 22:52) [3]

Не проверял и навскидку:

Wrd: array[0..2] of String = ("рублей", "рубль", "рубля");
...
Amount := Abs(Amount) mod 100;
Result := Wrd[Ord(
(Amount > 10) and (Amount < 20)
) * (
Ord(( (Amount + 3) mod 10) >= 6)
+ Ord(( (Amount + 3) mod 10) >= 7)
)]


 
Дмитрий СС   (2014-05-20 22:53) [4]

Вижу что уже неправильно знаки стоят, надеюсь идея понятна


 
Омлет ©   (2014-05-20 23:21) [5]

function PluralWord_omlet(Amount: Integer; const One, Two, Five: string): string;
var
 n: integer;
begin
 Amount := Abs(Amount);
 n := Amount mod 10;
 if (n > 4) or (n = 0) or (Amount mod 100 - n = 10) then
   Result := Five
 else if n > 1 then
   Result := Two
 else
   Result := One;
end;


 
Омлет ©   (2014-05-20 23:36) [6]

Только вот задачу не очень понял. Нужно сделать нечитабельно? Или неоптимально? Зачем это обфусцировать?


 
Sha ©   (2014-05-21 00:15) [7]

var c1, c2: cardinal;
begin;
 c2:=abs(Amount);
 c1:=c2 mod 10;
 c2:=c2 mod 100;
 if (c1=0) or (c1>=5) or (c1+10=c2) then Result:=Five
 else if (c1=1) then Result:=One
 else Result:=Two;
 end;


 
Sha ©   (2014-05-21 00:18) [8]

> Омлет ©   (20.05.14 23:21) [5]

практически совпало)
я свою выдернул из текущего проекта


 
Юрий Зотов ©   (2014-05-21 00:22) [9]

Проверочное слово - кочерга.
:o)


 
KSergey ©   (2014-05-21 08:00) [10]

> 0 -> 0
> 1..3- > 1
> 4...13 -> 2

Это 13 байт статического массива + простейшая команда доступа к массиву по индексу.
Во сколько байт скомпилируются приведенные выше куски кода?
И во сколько тактов процессора выполнятся?

Если входной параметр может выходить за диапазон [0..13] - тогда расширить таблицу до 16 элементов [0..15], в 14 и 15 запихать что-то разумное (видимо тоже 2, если я правильно понял) - и во входном параметре оставить 4 младших бита одной логической операцией.

Я к чему: все эти заумные алгоритмы и упражнения - абсолютно зряшнее времяубивание в рамках конечного времени жизни. Не в них то, что ожидается от программиста.


 
MBo ©   (2014-05-21 08:02) [11]

>Только вот задачу не очень понял. Нужно сделать нечитабельно? Или неоптимально? Зачем это обфусцировать?

Набор ифов понятнее.  А так - разные подходы интересно посмотреть (был когда-то впечатлен кучей невероятных методов посчитать DayOfWeek - с десяток не самых отмороженных есть в Pascal SWAG).


 
Омлет ©   (2014-05-21 08:12) [12]

> Sha ©   (21.05.14 00:15) [7]

Для 60% чисел mod 100 считать не нужно, поэтому мой вариант эффективнее )


 
Inovet ©   (2014-05-21 08:14) [13]

Посмотрел свой старый велосипед, ничего оригинального.

void __fastcall NumSpellE(__int64 n, String &w, Gender g, __int64 e, String s1, String s2, String s3)
{
 __int64 t;
 t = n / e; t %= 1000;
 if (n) {
   NumSpell3(t, w, g);
 }
 else {
   w = L"ноль";
 }

 String s;
 if (t > 0 || e == 1) {
   t %= 100;
   if (t < 11 || t > 19) {
     switch (t % 10) {
       case 1: s = s1; break;
       case 2:
       case 3:
       case 4: s = s2; break;
       default: s = s3;
     }
   }
   else s = s3;
 }
 if (!w.IsEmpty() && !s.IsEmpty()) w += " ";
 w += s;
}


 
Омлет ©   (2014-05-21 08:25) [14]

> KSergey ©   (21.05.14 08:00) [10]
> Не в них то, что ожидается от программиста.


(c) автор IncDay ))


 
KSergey ©   (2014-05-21 08:57) [15]

Ну вот, нарвался на авторские отчисления....
Куда гонорар автору засылать?


 
Sha ©   (2014-05-21 14:15) [16]

> Омлет ©   (21.05.14 08:12) [12]
> Для 60% чисел mod 100 считать не нужно, поэтому мой вариант эффективнее )

ну, тогда так:
function IntToName125Mod(i: integer): integer;
const
 b: array[0..99] of byte=(
//0 1 2 3 4 5 6 7 8 9
 2,0,1,1,1,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2,
 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2);
begin;
 Result:=b[abs(i) mod 100];
 end;


или даже так:
function IntToName125NoMod(i: integer): integer;
const
 b: array[0..99] of byte=(
//0 1 2 3 4 5 6 7 8 9
 2,0,1,1,1,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2,
 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2);
var
 j, k: integer;
begin;
 //i:=abs(i);
 j:=-(i shr 31);
 i:=i xor j - j;

 //i:=i-100*N;
 j:=i shr 7;
 k:=i shr 20;
 i:=i and $1FF;
 j:=j and $7FFC;
 k:=k and -4;
 j:=j * 3;
 i:=i + k;
 i:=i + j;

 //i:=i mod 100 для 0<=i<1024*100
 j:=(i + 1) * $A3D7 shr 22 * 100;
 i:=i - j;
 Result:=b[i];
 end;


 
Омлет ©   (2014-05-21 14:33) [17]

О, вот теперь действительно обфускация )


 
Rouse_ ©   (2014-05-21 18:43) [18]

Финтифлюшки это все :)

function PluralWord(Amount: Integer; const One, Two, Five: string): string;
begin
 Result := "руб.";
end;


 
brother ©   (2014-05-21 18:53) [19]

> "рубль", "рубля", "рублей"

выводить через #


 
Sha ©   (2014-05-22 01:00) [20]

Немного ускорил:
const
 Rests: array[0..99] of ShortInt=(
//0 1 2 3 4 5 6 7 8 9
 2,0,1,1,1,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2,
 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2, 2,0,1,1,1,2,2,2,2,2);

function IntToName125Mod(i: integer): integer; overload;
begin;
 Result:=Rests[abs(i) mod 100];
 end;

function IntToName125NoMod(i: integer): integer; overload;
var
 j, k: integer;
begin;
 //i:=abs(i);
 j:=-(i shr 31);
 i:=i xor j - j;

 //i:=i-100*N;
 j:=i shr 10;
 k:=i shr 20;
 i:=i and $0FFF; //биты 0..11
 j:=j and $0FFC; //биты 12..21 -> 2..11
 k:=k and $0FFC; //биты 22..31 -> 2..11
 i:=i - j;
 i:=i + k + 4100;

 //i:=i mod 100 для 0<=i<1024*100
 j:=(i + 1) * $A3D7 shr 22 * 100;
 i:=i - j;
 Result:=Rests[i];
 end;


Аналог для int64:
function IntToName125Mod(i64: int64): integer; overload;
begin;
 Result:=Rests[abs(i64) mod 100];
 end;

function IntToName125NoMod(i64: int64): integer; overload;
var
 i, j: integer;
begin;
 i64:=abs(i64);

 //i:=i-100*N;
 j:=i64;
 i:=j and $0FFF //биты 0..11
  - j shr 10 and $0FFC //биты 12..21 -> 2..11
  + j shr 20 and $0FFC //биты 22..31 -> 2..11
  + 32000;
 j:=i64 shr 32;
 if j<>0 then i:=i
               - j shl  2 and $0FFC //биты 32..41 -> 2..11
               + j shr  8 and $0FFC //биты 42..51 -> 2..11
               - j shr 18 and $3FFC;//биты 52..63 -> 2..13

 //i:=i mod 100 для 0<=i<1024*100
 j:=(i + 1) * $A3D7 shr 22 * 100;
 i:=i - j;
 Result:=Rests[i];
 end;


Как только начинаем работать со строками,
громадная разница в скорости скукоживается примерно до 2х раз:
const
 Names: array[0..2] of string= ("кочерга", "кочерги", "кочерег");

//пример вызова Memo1.Lines.Add(Format("%d %s",[i,IntToName125String(i,@Names[0])]));
function IntToName125String(i64: int64; Names: pString): string; overload;
var
 i, j: integer;
begin;
 i64:=abs(i64);

 //i:=i-100*N;
 j:=i64;
 i:=j and $0FFF //биты 0..11
  - j shr 10 and $0FFC //биты 12..21 -> 2..11
  + j shr 20 and $0FFC //биты 22..31 -> 2..11
  + 32000;
 j:=i64 shr 32;
 if j<>0 then i:=i
               - j shl  2 and $0FFC //биты 32..41 -> 2..11
               + j shr  8 and $0FFC //биты 42..51 -> 2..11
               - j shr 18 and $3FFC;//биты 52..63 -> 2..13

 //i:=i mod 100 для 0<=i<1024*100
 j:=(i + 1) * $A3D7 shr 22 * 100;
 i:=i - j;

 inc(Names,Rests[i]);
 Result:=Names^;
 end;

function IntToName125StringMod(i64: int64; Names: pString): string; overload;
begin;
 inc(Names,Rests[abs(i64 mod 100)]);
 Result:=Names^;
 end;

procedure TForm1.Button1Click(Sender: TObject);
const
 Count= 20000000;
var
 t: array[0..2] of cardinal;
 i: integer;
begin;
 t[0]:=GetTickCount;
 for i:=0 to Count-1 do IntToName125String(int64(MaxInt)*4,@Names[0]);
 t[1]:=GetTickCount;
 for i:=0 to Count-1 do IntToName125StringMod(int64(MaxInt)*4,@Names[0]);
 t[2]:=GetTickCount;
 Memo1.Lines.Add(IntToStr(t[1]-t[0]));
 Memo1.Lines.Add(IntToStr(t[2]-t[1]));
 end;


 
Владислав ©   (2014-05-22 01:24) [21]

Как автоматически просклонять "1 рубль", "2 рубля", "5 рублей" и т.д.:
function(Amount: Integer): string;
begin
 Result := "RUB " + IntToStr(Amount);
end;

Очень много валют так склоняется. ;)


 
Sha ©   (2014-05-22 01:44) [22]

жаль велосипеды и очень много других вещей так не склоняются


 
Омлет ©   (2014-05-22 12:07) [23]

> Sha ©   (22.05.14 01:00) [20]

Жесть )


 
MBo ©   (2014-05-22 12:12) [24]

>Очень много валют так склоняется. ;)
Мне нужно было вывести фразы типа "1 поток завершён, 2 потока завершены..."


 
oldman ©   (2014-05-22 14:50) [25]


> MBo ©   (22.05.14 12:12) [24]


"Потоков завершено: "+IntToStr(i)


 
Германн ©   (2014-05-22 15:00) [26]


> "Потоков завершено: "+IntToStr(i)
>

Магнитофон импортный. Два. (с)


 
Sha ©   (2014-05-22 15:31) [27]

))
"Потоков завершено: "+IntToStr(i)+" шт."


 
Омлет ©   (2014-05-22 20:38) [28]

"Несколько потоков завершено" )


 
brother ©   (2014-05-22 20:39) [29]

Сколько-то чего-то возможно завершилось...
:)


 
brother ©   (2014-05-22 20:42) [30]

> возможно

заменить на: скорее всего



Страницы: 1 вся ветка

Текущий архив: 2014.12.21;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.006 c
15-1400398597
dmk
2014-05-18 11:36
2014.12.21
HELP в Delphi XE6


2-1386138564
Fan
2013-12-04 10:29
2014.12.21
Отображение вибрации в делфи


1-1329071444
Proger254
2012-02-12 22:30
2014.12.21
Вызов функции чужого приложения


15-1400664566
Лактоза
2014-05-21 13:29
2014.12.21
CustomDrawTreeView.pas


15-1400617803
Юрий
2014-05-21 00:30
2014.12.21
С днем рождения ! 21 мая 2014 среда