Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2014.12.21;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.003 c
15-1400609609
MBo
2014-05-20 22:13
2014.12.21
Упростить числосклонятор до полной нечитабельности


11-1255823579
Ruzzz
2009-10-18 03:52
2014.12.21
Кол-во строк в Memo никогда не бывает 0


15-1399926602
Юрий
2014-05-13 00:30
2014.12.21
С днем рождения ! 13 мая 2014 вторник


15-1400445002
Юрий
2014-05-19 00:30
2014.12.21
С днем рождения ! 19 мая 2014 понедельник


15-1400787163
Дмитрий СС
2014-05-22 23:32
2014.12.21
Контрольное число





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский