Тупизмы в C#

 
1 2 3
+
-
edit
 

Balancer

администратор
★★★★☆
Изучаю тут C# (углубленно :D)

И с самого начала начал натыкаться на некоторые нелогичности в языке.

Вот, например, вопрос людям не знакомым с этим языком. Как думаете, почему в сложении тут возникает ошибка?

code csharp
  1. byte a, b, c;
  2. a = 5;
  3. b = 10;
  4. c = a + b;


Это не баг, это документированная особенность языка.
 

au

   
★★
Не могу знать! И понять! :)
 

Balancer

администратор
★★★★☆
au>Не могу знать! И понять! :)[»]

Ладно, не буду мучать :)

О! Под это дело написал тэг Форумы Авиабазы :) )

Кто хочет помучаться, тут не кликать! Спойлер! [показать]


Вот :)
 

Vale

Сальсолёт

Маразм. Впрочем, чего от "продукта" M$ ожидать-то?
"Не следуй за большинством на зло, и не решай тяжбы, отступая по большинству от правды" (Исх. 23:2)  

Balancer

администратор
★★★★☆
Vale>Впрочем, чего от "продукта" M$ ожидать-то?[»]

Всеобщего распространения :)
Впрочем, в целом штука, действительно хорошая :)
Хотя это больше достоинство не C#, а .NET :)
 

TEvg

аксакал

админ. бан
Кретинизм. Хорошо хоть я продукт тов. Вирта употребляю.
 

Balancer

администратор
★★★★☆
TEvg>Хорошо хоть я продукт тов. Вирта употребляю.[»]

Это в котором End то с точкой, то с точкой с запятой употребляется и отсутствуют функции с переменным числом параметров? :D
 

Vale

Сальсолёт

Дык какбытонибыло... всё равно для типичных юзверьских приложений останется мантра "интерфейс создаём вижуал дизайнером, код пишем на С++, критичые по скорости подпрограммки - пишем и отлаживаем на С, потом переписываем на ассемблер" ...

Сугубое, двугубое и многогубое ( © Куприн ) ПМСМ, разумеется.

Ну а про то, какой код генерируют компиляторы Паскаля, мы тихо и скорбно помолчим...
"Не следуй за большинством на зло, и не решай тяжбы, отступая по большинству от правды" (Исх. 23:2)  

TEvg

аксакал

админ. бан
>Это в котором End то с точкой, то с точкой с запятой употребляется и отсутствуют функции с переменным числом параметров?

Это в котором твой пример записывается:

var a, b, c : byte;

a := 5;
b := 10;
c := a + b;

И КОТОРЫЙ РАБОТАЕТ ВСЕГДА!
 

Balancer

администратор
★★★★☆
TEvg>a := 5;
TEvg>b := 10;
TEvg>c := a + b;
TEvg>И КОТОРЫЙ РАБОТАЕТ ВСЕГДА![»]

a := 200;
b := 200;
c := a + b;

Чему равен результат? :D
 

TEvg

аксакал

админ. бан
>Ну а про то, какой код генерируют компиляторы Паскаля, мы тихо и скорбно помолчим...

Чудесный код они генерируют.

Вот как выглядит Ромин пример:

mov al,$05
mov dl,$0a
lea ebx,[edx+eax]

Думаете Це сгенерирует код лучше?

ЗЫ Мой компилятор хотел этот пример вообще заоптимизировать - выбросить этот явно бессмысленный и неиспользуемый кусок кода. Поэтому приходится находить переменной с применение - например выводить значение на экран и т.п.
 
+
-
edit
 

Balancer

администратор
★★★★☆
Vale>Дык какбытонибыло... всё равно для типичных юзверьских приложений останется мантра "интерфейс создаём вижуал дизайнером, код пишем на С++, критичые по скорости подпрограммки - пишем и отлаживаем на С, потом переписываем на ассемблер" ...

Э... Даже сейчас "пишем и отлаживаем на C" - это процентов 5 проектов, "переписываем на ассемблер" - доли процента, хорошо, если сотые :)

Как я показывал тут в бенчмарктестах на этом же форуме:
— Скорость исполнение вычислительного кода на C# практически на одном уровне с C++ и уступает только O'Caml (ну, или чему-то типа SP-Forth, если оптимизатор хорошо сработает).
— Скорость работы лобовых решений на Ассемблере ниже, чем таких же решений на ЯВУ. Уже давно перешагнули уровень сложности процессоров, при которой качественный компилятор, в среднем, оптимизирует лучше, чем человек. В конце концов - это дело машины считать такты :) ИМХО, не за горами и тот день, когда код будет создаваться вообще с участием чего-нибудь подобного генетическим алгоритмам и человек тут окажется уже совсем за бортом.
— Упрощение написания программ путём повышения уровня компилятора позволяет не только писать на порядки более короткий и читабельный код но, из-за этого, зачастую, и более быстрый. Простой пример - предположим, что у нас нет базовых библиотек и нужно самому писать сортировку произвольных типов. На C/C++ на скорую руку будет выдано что-то типа сортировки пузырьком. И это будет с десяток строк кода. На OCaml в одну-две строки пишутся всякие qsort, втавками и т.п., которые работают просто на порядок быстрее. Даже если бы компилятор O'Caml генерил менее быстрый код, чем C++ (что не так), то в итоге мы бы получили выигрышь как по скорости разработки, так и по скорости выполнения конечного кода. C# тут, конечно, смотрится несколько хуже OCaml, но у него и заточка под несколько иное. И, в любом случае, при сопоставимой с C++ скорости, он смотрится намного лучше за счёт гораздо более мощного языка :)
 
Это сообщение редактировалось 20.08.2004 в 12:39
+
-
edit
 

Balancer

администратор
★★★★☆
TEvg>Вот как выглядит Ромин пример:
TEvg>mov al,$05
TEvg>mov dl,$0a
TEvg>lea ebx,[edx+eax]
TEvg>Думаете Це сгенерирует код лучше?

Любой современный CPP-компилер генерит подобное:

code text
  1. .
  2.   00000 6a 0f        push    15         ; 0000000fH
  3. [...]
  4.   00007 e8 00 00 00 00   call    _printf

 
+
-
edit
 

Balancer

администратор
★★★★☆
Жень, вот Паскаль у меня ещё в тестах не был :)

Хочешь "померяемся"? :)

1. 42-е число Фибоначчи рекурсивным методом. Т.е. fib(n) =
if n
2. Функция Аккермана от 3,8,8.
let rec a n x y =
   match (n, y) with
       (0, y) -> x+1
     | (1, 0) -> x
     | (2, 0) -> 0
     | (3, 0) -> 1
     | (n, 0) -> 2
     | (n, y) -> (a (n-1) (a n x (y-1)) x)
   ;;


Или, если так нагляднее, то на c++
code cpp
  1. #include <stdio.h>
  2.  
  3. int ackr(int n, int x, int y)
  4. {  
  5.     if(!n)
  6.         return x+1;
  7.  
  8.     if(y)
  9.         return ackr(n-1,ackr(n,x,y-1),x);
  10.    
  11.     switch(n)
  12.     {  
  13.         case 1: return x;
  14.         case 2: return 0;
  15.         case 3: return 1;
  16.     }
  17.     return 2;
  18. }
  19.  
  20. void main(void)
  21. {  
  22.     printf("%d\n",ackr(3,8,8));
  23. }


Давай, напишешь и скомпилишь их под Паскаль и приаттачишь exe-шники сюда. Я же приаттачу версии на O'Caml, VC7 и C# :)

Хочешь? :)
 
+
-
edit
 

Balancer

администратор
★★★★☆
TEvg>mov al,$05
TEvg>mov dl,$0a
TEvg>lea ebx,[edx+eax]

Скромные вопросы:
1. Что будет с этим кодом, если на входе в ah или dh что-то будет? :)
2. Зачем для вычисления суммы двух констант обирать ТРИ регистра? У нас что, RISC с 32-мя регистрами общего назначения? :)
 
+
-
edit
 

Balancer

администратор
★★★★☆
Кстати, Жень, за функцию Аккермана сразу не берись, ты в Паскале, ИМХО, так легко ~400Мб под стек не выделишь :)

Давай сразу 42-е число Фибоначчи.
code cpp
  1. #include <stdio.h>
  2.  
  3. int fib(int n)
  4. {
  5.     return n<2 ? 1 : fib(n-1)+fib(n-2);
  6. }
  7.  
  8. void main(void)
  9. {
  10.     printf("%d",fib(42));
  11. }


Вот для тестов и сравнений аттач рекордсмена - программы на SP-Forth 4

У меня оно считает 5 сек.
Прикреплённые файлы:
fib42_spforth4.zip (скачать) [28,1 кбайт, 73 загрузки] [attach=27409]
 
 
 
+
-
edit
 

Balancer

администратор
★★★★☆
Вот почти не уступающий ему пример на O'Caml (тоже 5.0 сек, но в сотых обычно чуть уступает Forth'у)

А, фиг с ним. Лови все :)

VC7 - 5.6сек
C# - 6.6сек в MS'овском JIT и 5.4 сек в JIT mono
Прикреплённые файлы:
fib42_ocaml.zip (скачать) [93,95 кбайт, 73 загрузки] [attach=27411]
 
fib42_vc7.zip (скачать) [14,88 кбайт, 64 загрузки] [attach=27412]
 
fib42_csharp.zip (скачать) [1,35 кбайт, 67 загрузок] [attach=27413]
 
 
 

TEvg

аксакал

админ. бан
Фиббоначи, 42-е число:

function fib(n:byte):integer;
begin
if n<2 then
Result:=1 else Result:=fib(n-1)+fib(n-2);
end;

генерируемый код:

push ebx
push esi
mov ebx,eax
cmp bl,$02
jnb fib + $11
mov eax,$00000001
pop esi
pop ebx
ret

Результат - 433.494.437
Израсходовано тактов проца - 863.031.753 - замеряно по RDTSC

Проц AMD XP 1400 МГц

Винда 2000-я многозадачная из-за чего количество тактов все время было разное, но не более чем на 1%.
 

TEvg

аксакал

админ. бан
>1. Что будет с этим кодом, если на входе в ah или dh что-то будет?

Чукча умный, чукча не дурак. Компилятор все учитывает. В данном случае он хотел вообще все команды повыкидывать, но т.к. запостить было бы нечего я его поправил, заставил считать.

>2. Зачем для вычисления суммы двух констант

Это не константы - это переменные. Паскаль - язык строгий.

>обирать ТРИ регистра? У нас что, RISC с 32-мя регистрами общего назначения?

?? Мне не жалко. Что у меня в проце регистров нет чтоль?
 
+
-
edit
 

Balancer

администратор
★★★★☆
TEvg>генерируемый код:
TEvg>push ebx
TEvg>push esi
TEvg>mov ebx,eax
TEvg>cmp bl,$02
TEvg>jnb fib + $11
TEvg>mov eax,$00000001
TEvg>pop esi
TEvg>pop ebx
TEvg>ret

Это, как минимум, не весь код.
Хотя бы потому, что в этом коде нет метки fib и непонятно, куда идёт переход.

TEvg>Результат - 433.494.437
TEvg>Израсходовано тактов проца - 863.031.753 - замеряно по RDTSC

Ты exe-шник приложи. Зазипуй - и в аттач.

>>1. Что будет с этим кодом, если на входе в ah или dh что-то будет?
TEvg>Чукча умный, чукча не дурак. Компилятор все учитывает.

Соовтетственно, и код будет совсем иной. Ибо в общем случае компилятору придётся ещё и регистры зачищать.

TEvg>Это не константы - это переменные.

Гм. Если 5 и 10 - это переменные, то опаньки :)

TEvg>?? Мне не жалко. Что у меня в проце регистров нет чтоль?

У тебя их всего четыре чистых РОН и два, которые таковыми можно назвать условно. Это ОЧЕНЬ мало. Сравни с 16..32 регистрами на почти любом RISC и даже с 8 практически равноправными регистрами архитектуры DEC 30-летней давности :) Основная проблема оптимизации - это именно оптимальное распределение регистров. И если на простую операцию их требуется аж три, то ни о какой глобальной оптимизации и речи быть уже не может.

Хотя, повторюсь, любой нормальный компилятор в этом примере с суммой байт не при исполнении считать их будет, а при компиляции. И это уже лет эдак с 5..7 :)
 

TEvg

аксакал

админ. бан
>Это, как минимум, не весь код.
>Хотя бы потому, что в этом коде нет метки fib и непонятно, куда идёт переход.

Это начинка процедуры, оттуда куда кидает управление call и до ret.

>Ты exe-шник приложи. Зазипуй - и в аттач.

Аллах.. ладно в понедельник.. ты лучше такты посчитай по RDTSC

>Гм. Если 5 и 10 - это переменные, то опаньки

Именно. Не 5 и 10, а - A,B,C : BYTE;
константы пишутся так const a=5, b=10;

>И если на простую операцию их требуется аж три, то ни о какой глобальной оптимизации и речи быть уже не может.

На Фиббоначах он же хороший код построил?
 
+
-
edit
 

SAA-977

новичок
Товарищ Balancer, а исходный текст программы - fib42_spforth4.zip
- на форте можно увидеть (для общего развития)?
 

Balancer

администратор
★★★★☆
TEvg>Это начинка процедуры, оттуда куда кидает управление call и до ret.

Там нет никакого вычитания. Нет повторного вызова процедуры. А область начало процедуры + 0x11 явно выходит за пределы приведённого кода. Ты привёл только начальный её фрагмент.

TEvg>Аллах.. ладно в понедельник.. ты лучше такты посчитай по RDTSC

Как я, по-твоему, буду считать такты в C#? :D

>>Гм. Если 5 и 10 - это переменные, то опаньки
TEvg>Именно. Не 5 и 10, а - A,B,C : BYTE;

Если 5 - константа, то и b = 5 - тоже константа. Любой нормальный компилятор должен это учитывать при отпимизации.

TEvg>На Фиббоначах он же хороший код построил?[»]

Нет, примитивный и потому медленный. Ни распараллеливания, ни предвычислений, ни раскрутки. Сравни с кодом O'Caml:
code 6502acme
  1.         PUBLIC  _Fib__fib_57
  2. _Fib__fib_57:
  3.         sub     esp, 8
  4. L101:
  5.         cmp     eax, 5
  6.         jge     L100
  7.         mov     eax, 3
  8.         add    esp, 8
  9.         ret
  10. L100:
  11.         mov     DWORD PTR 0[esp], eax
  12.         add     eax, -4
  13.         call    _Fib__fib_57
  14. L102:
  15.         mov     DWORD PTR 4[esp], eax
  16.         mov     eax, DWORD PTR 0[esp]
  17.         add     eax, -2
  18.         call    _Fib__fib_57
  19. L103:
  20.         mov     ebx, DWORD PTR 4[esp]
  21.         add     eax, ebx
  22.         dec     eax
  23.         add    esp, 8
  24.         ret


или CPP
code text
  1. ?fib@@YIHH@Z PROC NEAR                                  ; fib, COMDAT
  2. ; _n$ = ecx
  3.  
  4. ; 4    : {
  5.  
  6.   00000 57               push    edi
  7.   00001 8b f9            mov     edi, ecx
  8.  
  9. ; 5    :     return n<2 ? 1 : fib(n-1)+fib(n-2);
  10.  
  11.   00003 83 ff 02         cmp     edi, 2
  12.   00006 7d 07            jge     SHORT $L623
  13.   00008 b8 01 00 00 00   mov     eax, 1
  14.   0000d 5f               pop     edi
  15.  
  16. ; 6    : }
  17.  
  18.   0000e c3               ret     0
  19. $L623:
  20.   0000f 56               push    esi
  21.  
  22. ; 5    :     return n<2 ? 1 : fib(n-1)+fib(n-2);
  23.  
  24.   00010 8d 4f fe         lea     ecx, DWORD PTR [edi-2]
  25.   00013 e8 00 00 00 00   call    ?fib@@YIHH@Z           ; fib
  26.   00018 8d 4f ff         lea     ecx, DWORD PTR [edi-1]
  27.   0001b 8b f0            mov     esi, eax
  28.   0001d e8 00 00 00 00   call    ?fib@@YIHH@Z           ; fib
  29.   00022 03 f0            add     esi, eax
  30.   00024 8b c6            mov     eax, esi
  31.   00026 5e               pop     esi
  32.   00027 5f               pop     edi
  33.  
  34. ; 6    : }
  35.  
  36.   00028 c3               ret     0
  37. ?fib@@YIHH@Z ENDP                                       ; fib
  38.  
  39. ; ---------------------------------------------------
  40.  
  41.   00000 b9 29 00 00 00   mov     ecx, 41                        ; 00000029H
  42.   00005 e8 00 00 00 00   call    ?fib@@YIHH@Z           ; fib
  43.   0000a b9 28 00 00 00   mov     ecx, 40                        ; 00000028H
  44.   0000f 8b d0            mov     edx, eax
  45.   00011 e8 00 00 00 00   call    ?fib@@YIHH@Z           ; fib
  46.   00016 03 d0            add     edx, eax
 
+
-
edit
 

Balancer

администратор
★★★★☆
SAA-977>Товарищ Balancer, а исходный текст программы - fib42_spforth4.zip
SAA-977>- на форте можно увидеть (для общего развития)?[»]

Да я уже приводил в соответствующем топике (по сравнению скорости)

code forth
  1. : FIB ( N1 -- N2 )
  2.     DUP 2 < IF
  3.         DROP 1 EXIT
  4.     THEN
  5.     1- DUP RECURSE
  6.     SWAP 1- RECURSE
  7.     +
  8. ;
  9.  
  10. : MAIN    42 FIB . BYE ;
  11.  
  12. ' MAIN TO <MAIN>  S" fib.exe" SAVE BYE
 
+
-
edit
 

Balancer

администратор
★★★★☆
TEvg>Израсходовано тактов проца - 863.031.753 - замеряно по RDTSC
TEvg>Проц AMD XP 1400 МГц

При рекурсивном вычислении fib(42) происходит 866988873 вызовов функции. Хочешь сказать, что на одну итерацию у тебя уходит 863031753/866988873 = 1.00 такт?? На два вычитания, сложение, организацию вложенного вызова?
 
1 2 3

в начало страницы | новое
 
Поиск
Настройки
Твиттер сайта
Статистика
Рейтинг@Mail.ru