Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: WINAVR rand()
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
heburashka
Здравствуйте.

Пытаюсь заставить rand() генерить в узком диапазоне 0-9

выставлял RAND_MAX 0b00001001

в пректе и в <stdlib.h>

не работает.

help


спасибо.
zltigo
Цитата(heburashka @ Apr 19 2009, 17:49) *
Пытаюсь заставить rand()...

Не надо заставлять. Просто прочитайте описание rand() в любой из книжек.
value = rand() % 10;
Moderator:
Просьба не загромождать основные ветки (в частности "AVR") форума простейшими вопросами.
heburashka
Цитата(zltigo @ Apr 19 2009, 18:11) *
Не надо заставлять. Просто прочитайте описание rand() в любой из книжек.
value = rand() % 10;
Moderator:
Просьба не загромождать основные ветки (в частности "AVR") форума простейшими вопросами.



уважаемый модератор, мой вопрос задан поскольку механизмы описанные в литературе не работают.

под "заставить" подразумевается получить результат в соответствии с механизмом работы, а не то что вы подумали....

value = rand() % 10;

это предложенный вариант решения ?

в документации нет ничего подобного.
singlskv
Цитата(zltigo @ Apr 19 2009, 19:11) *
value = rand() % 10;
Очень не эфективно...
Надо как-нить так:
Код
  value = rand();
  value = (value & 0x0F) > 9 ? (value - 10) : value;

раз в 10-20 быстрее...
zltigo
Цитата(heburashka @ Apr 19 2009, 18:31) *
получить результат в соответствии с механизмом работы, а не то что вы подумали....

Вот именно с этим самым "механизмом" Вам и следует прежде всего ознакомиться, ибо он работает, "как описано в литературе". А "что вы подумали", залезть и подделать цифирки в системном заголовочном файле, которые дают программисту информацию о дианазоне генерирумых rand() чисел, то это уже чисто Ваши проблемы.
heburashka
Цитата(singlskv @ Apr 19 2009, 18:35) *
Очень не эфективно...
Надо как-нить так:
Код
  value = rand();
  value = (value & 0x0F) > 9 ? (value - 10) : value;

раз в 10-20 быстрее...


спасибо.

не понятно почему через rand_max не работает.....

не подскажете?
zltigo
Цитата(heburashka @ Apr 19 2009, 18:33) *
это предложенный вариант решения ?

Один из - канонический, так сказать.
heburashka
Цитата(zltigo @ Apr 19 2009, 18:40) *
Вот именно с этим самым "механизмом" Вам и следует прежде всего ознакомиться, ибо он работает, "как описано в литературе". А "что вы подумали", залезть и подделать цифирки в системном заголовочном файле, которые дают программисту информацию о дианазоне генерирумых rand() чисел, то это уже чисто Ваши проблемы.



дык мне и нужен диапазон 0-9 ... ?


RAND_MAX что то другое задает ?
zltigo
Цитата(heburashka @ Apr 19 2009, 18:41) *
не понятно почему через rand_max не работает.....

Потому, что НЕ ДОЛЖЕН он работать в соответствии с Вашими фантазиями sad.gif. Перечитайте пост №5.
heburashka
Цитата(heburashka @ Apr 19 2009, 18:44) *
дык мне и нужен диапазон 0-9 ... ?


RAND_MAX что то другое задает ?




проверил rand() % 10 - работает.

??? RAND_MAX что то другое задает ?
zltigo
Цитата(heburashka @ Apr 19 2009, 18:44) *
RAND_MAX что то другое задает ?

Читайте по буквам еще раз - он вообще ничего не задает - он информирует.
Может Вы еще хотите подделав пару чисел с заголовочных файлах сделать из Вашего AVR 64-битный процессор? Подделать - легко, только ведь "работать" тоже не будет.
Системные заголовочные файлы вообще-то НИКОГДА править нельзя, ну если,конечно Вы не собираетесь после этого пересобрать компилятор/библилиотеки.
Сергей Борщ
Цитата(heburashka @ Apr 19 2009, 18:41) *
не понятно почему через rand_max не работает.....
Потому что RAND_MAX никак не влияет и не может влиять на работу библиотечной функции rand(). Через эту константу разработчики библиотеки сообщают ее пользователю, в каком диапазоне функция генерит свой результат. Повлиять на генерируемый функцией результат вы можете, изменив исходный код функции и перекомпилировав библотеку. А вот привести полученный от нее результат к интересующему вас диапазону вполне возможно. Пример - код zltigo. 

Цитата(singlskv @ Apr 19 2009, 18:35) *
Надо как-нить так:
Код
 value = rand();
  value = (value & 0x0F) > 9 ? (value - 10) : value;
раз в 10-20 быстрее...
Быстрее будет, но вот о нормальном распределении полученных значений можно забыть.
heburashka
Цитата(zltigo @ Apr 19 2009, 18:46) *
Потому, что НЕ ДОЛЖЕН он работать в соответствии с Вашими фантазиями sad.gif. Перечитайте пост №5.



У меня нет фантазий на эту тему и на тему "заставить", у меня есть описание функции:

Возвращает псевдослучайное число в диапазоне от 0 до RAND_MAX.... и мне непонятно почему не работает...
zltigo
Цитата(heburashka @ Apr 19 2009, 18:53) *
...и мне непонятно почему не работает...

Все. Финиш sad.gif
singlskv
Цитата(heburashka @ Apr 19 2009, 19:41) *
не понятно почему через rand_max не работает.....

не подскажете?

Попробую подсказать...
rand принципиально рассчитан на диапазон 0 - 2^N
это связанно с тем что нужно пробегать ВСЕ значения в этом диапазоне.
10 явно не подходит...

вот Вам реализация rand под WinAVR:
CODE

static int
do_rand(unsigned long *ctx)
{
#ifdef USE_WEAK_SEEDING
/*
* Historic implementation compatibility.
* The random sequences do not vary much with the seed,
* even with overflowing.
*/
return ((*ctx = *ctx * 1103515245L + 12345L) %
((unsigned long)RAND_MAX + 1));
#else /* !USE_WEAK_SEEDING */
/*
* Compute x = (7^5 * x) mod (2^31 - 1)
* wihout overflowing 31 bits:
* (2^31 - 1) = 127773 * (7^5) + 2836
* From "Random number generators: good ones are hard to find",
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
* October 1988, p. 1195.
*/
long hi, lo, x;

x = *ctx;
/* Can't be initialized with 0, so use another value. */
if (x == 0)
x = 123459876L;
hi = x / 127773L;
lo = x % 127773L;
x = 16807L * lo - 2836L * hi;
if (x < 0)
x += 0x7fffffffL;
return ((*ctx = x) % ((unsigned long)RAND_MAX + 1));
#endif /* !USE_WEAK_SEEDING */
}


int
rand_r(unsigned long *ctx)
{
return do_rand(ctx);
}


static unsigned long next = 1;

int
rand(void)
{
return do_rand(&next);
}

void
srand(unsigned int seed)
{
next = seed;
}
ARV
на спидометре машины написано 0..200 км/ч. это значит, она может ехать от 0 до 200 км/ч. если вы на спидометре нарисуете вместо 200, например 500 или наоборот 10 - думаете, это повлияет на поведение машины?

константа в хидере уведомляет вас о мощности мотора, сиречь, о свойствах функции. но сама функция от этой константы не зависит - это просто маркировка на спидометре.
heburashka
Цитата(Сергей Борщ @ Apr 19 2009, 18:53) *
Потому что RAND_MAX никак не влияет и не может влиять на работу библиотечной функции rand(). Через эту константу разработчики библиотеки сообщают ее пользователю, в каком диапазоне функция генерит свой результат. Повлиять на генерируемый функцией результат вы можете, изменив исходный код функции и перекомпилировав библотеку. А вот привести полученный от нее результат к интересующему вас диапазону вполне возможно. Пример - код zltigo. 

Быстрее будет, но вот о нормальном распределении полученных значений можно забыть.



У меня в источнике есть вот это

Математическое макроопределение

#define RAND_MAX 0X.......

наибольшее значение генерируемое rand


От этого и вопросы задавал.


Всем спасибо, а с каких пор зазорно стало спрашивать ?

Уважаемый модератор не стоит на людей бросаться.

Цитата(zltigo @ Apr 19 2009, 18:56) *
Все. Финиш sad.gif



товарищ устал rolleyes.gif

СПАСИБО ВСЕМ.
singlskv
Цитата(Сергей Борщ @ Apr 19 2009, 19:53) *
Быстрее будет, но вот о нормальном распределении полученных значений можно забыть.

Ну хорошо, согласен, нормальное распеределение чуть подпортил...
Но тогда вот так:
Код
value = rand() * 10;
value = value >> 15;
где 15 это разрядность RAND_MAX
И все равно в 10-20 раз быстрее...
heburashka
напоследок.


RAND_MAX восстанавливать с прежним значением не нужно, раз оно носит чисто информационный характер и ничего страшного не произойдет ?

про машину ...здорово rolleyes.gif
ARV
Цитата(heburashka @ Apr 19 2009, 20:19) *
RAND_MAX восстанавливать с прежним значением не нужно, раз оно носит чисто информационный характер и ничего страшного не произойдет ?
формально - ничего страшного. но лучше восстановить, ибо кто знает, какие проекты вы будете собирать в будущем - возможно среди них попадутся те, которые используют эту константу...
zltigo
Цитата(singlskv @ Apr 19 2009, 19:15) *
Код
value = rand() * 10;
value = value >> 15;
где 15 это разрядность RAND_MAX
И все равно в 10-20 раз быстрее...

Прям сейчас представил, как будет "выстрее" у AVR c 32bitным value smile.gif.
heburashka
Цитата(ARV @ Apr 19 2009, 19:23) *
формально - ничего страшного. но лучше восстановить, ибо кто знает, какие проекты вы будете собирать в будущем - возможно среди них попадутся те, которые используют эту константу...


спасибо.
singlskv
Цитата(zltigo @ Apr 19 2009, 20:27) *
Прям сейчас представил, как будет "выстрее" у AVR c 32bitным value smile.gif.
Пробуем ? Вы с %10 я с умножением
таргет для однозначности например мега8.

Или cлабо ?
zltigo
Цитата(singlskv @ Apr 19 2009, 19:38) *
Или cлабо ?

Скорее всего лениво sad.gif. Если уж беретесь проверить,то давайте оба варианта ввиде листинга сюда.
heburashka
singlskv

спасибо за #15 пост !

наши однозначно быстрее rolleyes.gif
zltigo
Цитата(heburashka @ Apr 19 2009, 19:44) *
спасибо за #15 пост !

Если-бы он еще имел какое-то отношение к сути проблемы а не к дополнительным ограничениям конкретной реализации. Похоже,что после этого поста
heburashka окончательно запутался в причинах sad.gif.
singlskv
Цитата(zltigo @ Apr 19 2009, 20:43) *
Скорее всего лениво sad.gif. Если уж беретесь проверить,то давайте оба варианта ввиде листинга сюда.
Дык запросто, хотя и лениво было...
чтоб меня не обвиняли в неправильном компиляторе, поставил IAR и сделал в нем:
Код
#include <stdlib.h>

int A;
volatile char B;

int main( void )
{
  long c;

  A = rand();
  B = A % 10;
  
  A = rand();
  c = A * 20UL;
  B = c >> 16;

  return 0;
}

CODE

10: A = rand();
+00000019: D016 RCALL PC+0x0017 Relative call subroutine
11: B = A % 10;
+0000001A: E04A LDI R20,0x0A Load immediate
+0000001B: E050 LDI R21,0x00 Load immediate
+0000001C: 8100 LDD R16,Z+0 Load indirect with displacement
+0000001D: D040 RCALL PC+0x0041 Relative call subroutine
+0000001E: 93400066 STS 0x0066,R20 Store direct to data space
13: A = rand();
+00000020: D00F RCALL PC+0x0010 Relative call subroutine
15: B = c >> 16;
+00000021: 8100 LDD R16,Z+0 Load indirect with displacement
+00000022: 2F21 MOV R18,R17 Copy register
+00000023: 0F22 LSL R18 Logical Shift Left
+00000024: 0B22 SBC R18,R18 Subtract with carry
+00000025: 2F32 MOV R19,R18 Copy register
+00000026: E144 LDI R20,0x14 Load immediate
+00000027: E050 LDI R21,0x00 Load immediate
+00000028: E060 LDI R22,0x00 Load immediate
+00000029: E070 LDI R23,0x00 Load immediate
+0000002A: D046 RCALL PC+0x0047 Relative call subroutine
+0000002B: 93200066 STS 0x0066,R18 Store direct to data space
17: return 0;
+0000002D: E000 LDI R16,0x00 Load immediate
+0000002E: E010 LDI R17,0x00 Load immediate
+0000002F: 9508 RET Subroutine return
@00000030: _..X_RSTACK_BASE
---- No Source ------------------------------------------------------------------------------------
+00000030: D062 RCALL PC+0x0063 Relative call subroutine
+00000031: E6E4 LDI R30,0x64 Load immediate
+00000032: E0F0 LDI R31,0x00 Load immediate
+00000033: 8300 STD Z+0,R16 Store indirect with displacement
+00000034: 8311 STD Z+1,R17 Store indirect with displacement
+00000035: 9508 RET Subroutine return
@00000036: ?C_FUNCALL
+00000036: 0000 NOP No operation
@00000037: __exit
+00000037: 9588 SLEEP Sleep
+00000038: CFFE RJMP PC-0x0001 Relative jump
@00000039: ?C_STARTUP
+00000039: EA06 LDI R16,0xA6 Load immediate
+0000003A: BF0D OUT 0x3D,R16 Out to I/O location
+0000003B: E000 LDI R16,0x00 Load immediate
+0000003C: BF0E OUT 0x3E,R16 Out to I/O location
+0000003D: E8C7 LDI R28,0x87 Load immediate
+0000003E: E0D0 LDI R29,0x00 Load immediate
@0000003F: ?call_low_level_init
+0000003F: D051 RCALL PC+0x0052 Relative call subroutine
@00000040: ?need_segment_init
+00000040: 2300 TST R16 Test for Zero or Minus
+00000041: F009 BREQ PC+0x02 Branch if equal
+00000042: D074 RCALL PC+0x0075 Relative call subroutine
@00000043: ?cstartup_call_main
+00000043: DFD5 RCALL PC-0x002A Relative call subroutine
+00000044: DFF1 RCALL PC-0x000E Relative call subroutine
+00000045: CFF0 RJMP PC-0x000F Relative jump
@00000046: ?US_DIVMOD_L02
+00000046: 2400 CLR R0 Clear Register
+00000047: 2411 CLR R1 Clear Register
+00000048: E0EF LDI R30,0x0F Load immediate
+00000049: 1F00 ROL R16 Rotate Left Through Carry
+0000004A: 1F11 ROL R17 Rotate Left Through Carry
+0000004B: 1C00 ROL R0 Rotate Left Through Carry
+0000004C: 1C11 ROL R1 Rotate Left Through Carry
+0000004D: 1604 CP R0,R20 Compare
+0000004E: 0615 CPC R1,R21 Compare with carry
+0000004F: F010 BRCS PC+0x03 Branch if carry set
@00000050: _..X_SRAM_TSIZE
+00000050: 1A04 SUB R0,R20 Subtract without carry
+00000051: 0A15 SBC R1,R21 Subtract with carry
+00000052: 95EA DEC R30 Decrement
+00000053: F7AA BRPL PC-0x0A Branch if plus
+00000054: 1F00 ROL R16 Rotate Left Through Carry
+00000055: 1F11 ROL R17 Rotate Left Through Carry
+00000056: 01A0 MOVW R20,R0 Copy register pair
+00000057: 9500 COM R16 One's complement
+00000058: 9510 COM R17 One's complement
+00000059: 9508 RET Subroutine return
+0000005A: 9551 NEG R21 Two's complement
+0000005B: 9541 NEG R20 Two's complement
+0000005C: 4050 SBCI R21,0x00 Subtract immediate with carry
+0000005D: 9508 RET Subroutine return
@0000005E: ?SS_DIVMOD_L02
+0000005E: 27FF CLR R31 Clear Register
+0000005F: 2355 TST R21 Test for Zero or Minus
+00000060: F412 BRPL PC+0x03 Branch if plus
+00000061: 60F1 ORI R31,0x01 Logical OR with immediate
+00000062: DFF7 RCALL PC-0x0008 Relative call subroutine
+00000063: 2311 TST R17 Test for Zero or Minus
+00000064: F412 BRPL PC+0x03 Branch if plus
+00000065: 95F0 COM R31 One's complement
+00000066: D006 RCALL PC+0x0007 Relative call subroutine
+00000067: DFDE RCALL PC-0x0021 Relative call subroutine
+00000068: FDF0 SBRC R31,0 Skip if bit in register cleared
+00000069: D003 RCALL PC+0x0004 Relative call subroutine
+0000006A: FDF1 SBRC R31,1 Skip if bit in register cleared
+0000006B: CFEE RJMP PC-0x0011 Relative jump
+0000006C: 9508 RET Subroutine return
+0000006D: 9511 NEG R17 Two's complement
+0000006E: 9501 NEG R16 Two's complement
+0000006F: 4010 SBCI R17,0x00 Subtract immediate with carry
+00000070: 9508 RET Subroutine return
@00000071: ?L_EC_MUL_L03
+00000071: 2422 CLR R2 Clear Register
+00000072: 9F34 MUL R19,R20 Multiply unsigned
+00000073: 2D30 MOV R19,R0 Copy register
+00000074: 9F25 MUL R18,R21 Multiply unsigned
+00000075: 0D30 ADD R19,R0 Add without carry
+00000076: 9F16 MUL R17,R22 Multiply unsigned
+00000077: 0D30 ADD R19,R0 Add without carry
+00000078: 9F07 MUL R16,R23 Multiply unsigned
+00000079: 0D30 ADD R19,R0 Add without carry
+0000007A: 9F24 MUL R18,R20 Multiply unsigned
+0000007B: 2D20 MOV R18,R0 Copy register
+0000007C: 0D31 ADD R19,R1 Add without carry
+0000007D: 9F15 MUL R17,R21 Multiply unsigned
+0000007E: 0D20 ADD R18,R0 Add without carry
+0000007F: 1D31 ADC R19,R1 Add with carry
+00000080: 9F06 MUL R16,R22 Multiply unsigned
+00000081: 0D20 ADD R18,R0 Add without carry
+00000082: 1D31 ADC R19,R1 Add with carry
+00000083: 9F14 MUL R17,R20 Multiply unsigned
+00000084: 2D10 MOV R17,R0 Copy register
+00000085: 0D21 ADD R18,R1 Add without carry
+00000086: 1D32 ADC R19,R2 Add with carry
+00000087: 9F05 MUL R16,R21 Multiply unsigned
+00000088: 0D10 ADD R17,R0 Add without carry
+00000089: 1D21 ADC R18,R1 Add with carry
+0000008A: 1D32 ADC R19,R2 Add with carry
+0000008B: 9F04 MUL R16,R20 Multiply unsigned
+0000008C: 2D00 MOV R16,R0 Copy register
+0000008D: 0D11 ADD R17,R1 Add without carry
+0000008E: 1D22 ADC R18,R2 Add with carry
+0000008F: 1D32 ADC R19,R2 Add with carry
+00000090: 9508 RET Subroutine return
@00000091: __low_level_init
+00000091: E001 LDI R16,0x01 Load immediate
+00000092: 9508 RET Subroutine return
@00000093: rand
+00000093: E64D LDI R20,0x6D Load immediate
+00000094: E45E LDI R21,0x4E Load immediate
+00000095: EC66 LDI R22,0xC6 Load immediate
+00000096: E471 LDI R23,0x41 Load immediate
+00000097: E6E0 LDI R30,0x60 Load immediate
+00000098: E0F0 LDI R31,0x00 Load immediate
+00000099: 8100 LDD R16,Z+0 Load indirect with displacement
+0000009A: 8111 LDD R17,Z+1 Load indirect with displacement
+0000009B: 8122 LDD R18,Z+2 Load indirect with displacement
+0000009C: 8133 LDD R19,Z+3 Load indirect with displacement
+0000009D: DFD3 RCALL PC-0x002C Relative call subroutine
+0000009E: 5C07 SUBI R16,0xC7 Subtract immediate
+0000009F: 4C1F SBCI R17,0xCF Subtract immediate with carry
+000000A0: 4F2F SBCI R18,0xFF Subtract immediate with carry
+000000A1: 4F3F SBCI R19,0xFF Subtract immediate with carry
+000000A2: 8300 STD Z+0,R16 Store indirect with displacement
+000000A3: 8311 STD Z+1,R17 Store indirect with displacement
+000000A4: 8322 STD Z+2,R18 Store indirect with displacement
+000000A5: 8333 STD Z+3,R19 Store indirect with displacement
+000000A6: 0189 MOVW R16,R18 Copy register pair
+000000A7: 771F ANDI R17,0x7F Logical AND with immediate
+000000A8: 9508 RET Subroutine return
@000000A9: __memclr
+000000A9: E020 LDI R18,0x00 Load immediate
+000000AA: D006 RCALL PC+0x0007 Relative call subroutine
+000000AB: F7E9 BRNE PC-0x02 Branch if not equal
+000000AC: 9508 RET Subroutine return
@000000AD: __flashcpy
+000000AD: 9125 LPM R18,Z+ Load program memory and postincrement
+000000AE: D002 RCALL PC+0x0003 Relative call subroutine
+000000AF: F7E9 BRNE PC-0x02 Branch if not equal
+000000B0: 9508 RET Subroutine return
+000000B1: 932D ST X+,R18 Store indirect and postincrement
+000000B2: 5001 SUBI R16,0x01 Subtract immediate
+000000B3: 4010 SBCI R17,0x00 Subtract immediate with carry
+000000B4: 2F20 MOV R18,R16 Copy register
+000000B5: 2B21 OR R18,R17 Logical OR
+000000B6: 9508 RET Subroutine return
@000000B7: __segment_init
+000000B7: E286 LDI R24,0x26 Load immediate
+000000B8: E090 LDI R25,0x00 Load immediate
+000000B9: 01FC MOVW R30,R24 Copy register pair
+000000BA: 9105 LPM R16,Z+ Load program memory and postincrement
+000000BB: 9114 LPM R17,Z Load program memory
+000000BC: 01FC MOVW R30,R24 Copy register pair
+000000BD: 9632 ADIW R30,0x02 Add immediate to word
+000000BE: 91A5 LPM R26,Z+ Load program memory and postincrement
+000000BF: 91B4 LPM R27,Z Load program memory
+000000C0: 01FC MOVW R30,R24 Copy register pair
+000000C1: 9634 ADIW R30,0x04 Add immediate to word
+000000C2: 9125 LPM R18,Z+ Load program memory and postincrement
+000000C3: 9134 LPM R19,Z Load program memory
+000000C4: 2F42 MOV R20,R18 Copy register
+000000C5: 2B43 OR R20,R19 Logical OR
+000000C6: F019 BREQ PC+0x04 Branch if equal
+000000C7: 01F9 MOVW R30,R18 Copy register pair
+000000C8: DFE4 RCALL PC-0x001B Relative call subroutine
+000000C9: C001 RJMP PC+0x0002 Relative jump
+000000CA: DFDE RCALL PC-0x0021 Relative call subroutine
+000000CB: 9606 ADIW R24,0x06 Add immediate to word
+000000CC: E010 LDI R17,0x00 Load immediate
+000000CD: 3382 CPI R24,0x32 Compare with immediate
+000000CE: 0791 CPC R25,R17 Compare with carry
+000000CF: F348 BRCS PC-0x16 Branch if carry set
+000000D0: 9508 RET Subroutine return
+000000D1: 0001 ??? Data or unknown opcode
+000000D2: 0000 NOP No operation
+000000D3: DFDE RCALL PC-0x0021 Relative call subroutine
+000000D4: 9606 ADIW R24,0x06 Add immediate to word
+000000D5: E010 LDI R17,0x00 Load immediate
+000000D6: 3382 CPI R24,0x32 Compare with immediate
+000000D7: 0791 CPC R25,R17 Compare with carry
+000000D8: F348 BRCS PC-0x16 Branch if carry set
+000000D9: 9508 RET Subroutine return


Да, ошибся smile.gif всего в 4 раза быстрее, правда я еще нифига не оптимизировал...
в 10 раз легко...
zltigo
Цитата(singlskv @ Apr 19 2009, 21:53) *
Да, ошибся smile.gif всего в 4 раза быстрее, правда я еще нифига не оптимизировал...
в 10 раз легко...

Какое отношение имеют ошметки какого-то листинга к выводам о 4x выигрыше в чем-то?
Раз уж плавно на IAR перешли, то вот быстренько скопипастил исходник библиотечной IAR функции:
Код
;-------------------------------------------------------------
; US_DIVMOD_L02
; 'short' (i.e. 16 bit) unsigned division and modulo
; On call: PW = dividend (i.e. number to be divided by divisor)
;      QW = divisor
; On return: PW = quotient, QW = remainder
;
; NOTE: This subroutine is also called from SS_DIVMOD_L02
;
; Destroys: P0 P1 Q0 Q1 T0 T1 Z0
;
; SIZE: 42 bytes
;
; TBD: The optimization for speed when Q1 .NE. 0, described in the
;      algorithm has not been implemented here, it will add some
;      8 instructions to the code.

    MODULE  ?US_DIVMOD_L02
    PUBLIC  ?US_DIVMOD_L02
    RSEG    CODE:CODE:NOROOT(1)

; Do not change this function without changing the information in the compiler. 2004-02-26
?US_DIVMOD_L02:
    CLR     T0    ; Clear remainder
    CLR     T1    ;     - "" -
    LDI     Z0,15     ; Loop counter
A25:    
    ROL     P0    ; Shift quotient/dividend
    ROL     P1    ;
    ROL     T0    ; --> into remainder
    ROL     T1    ;
    CP      T0,Q0     ; Is remainder < divisor ?
    CPC     T1,Q1
    BRLO    A25_1     ; Yes, but carry 0 expected by algorithm,
              ; is actually 1 here.
;
; Here if time to subtract, i.e. value in remainder is equal to
; or larger than divisor.
;
    SUB     T0,Q0
    SBC     T1,Q1     ; Carry 1 expected, is actually 0 !
A25_1:  
    DEC     Z0    ; Does not affect carry
    BRPL    A25; All done
B25:    
    ROL     P0    ; Only quotient shifted
    ROL     P1    ; in last step.
#ifdef __HAS_ENHANCED_CORE__
    MOVW    Q1:Q0,T1:T0; Remainder
#else
    MOV     Q0,T0     ; Remainder
    MOV     Q1,T1
#endif
    COM     P0    ; Correct for inverse carry setting
    COM     P1
    RET

    ENDMOD

Которая собственно все и делает.
Не подарок,конечно, для AVR получается sad.gif
То, что Вы предлагаете:
Код
unsigned long value = rand() * 10;
value = value >> 15;

Компильните и нормальный листинг выложите сюда. Тогда и можно будет говорить о 10...4 разнице.
P.S.
А для младших-то AVR умножение эмулировать придется smile.gif
singlskv
Цитата(zltigo @ Apr 19 2009, 23:26) *
Какое отношение имеют ошметки какого-то листинга к выводам о 4x выигрыше в чем-то?
Стоп, я скомпилировал именно IAR компилятором и именно тот исходник который показал...
И листинг выложен полный... копия из AVR Studio, так что не надо ля-ля...
Цитата
Раз уж плавно на IAR перешли, то вот быстренько скопипастил исходник библиотечной IAR функции:
Которая собственно все и делает.
Не подарок,конечно, для AVR получается sad.gif

Ну и ... ?
Цитата
То, что Вы предлагаете:
Код
unsigned long value = rand() * 10;
value = value >> 15;

Компильните и нормальный листинг выложите сюда. Тогда и можно будет говорить о 10...4 разнице.

Дык еще раз предлагаю, делаем 2 проекта и показываем листинг и количество тактов...
Или снова слабо и тока ля-ля...



Цитата(zltigo @ Apr 19 2009, 23:26) *
А для младших-то AVR умножение эмулировать придется smile.gif
Несомненно делить там будет намного выгоднее 1111493779.gif
zltigo
Цитата(singlskv @ Apr 19 2009, 22:41) *
И листинг выложен полный... копия из AVR Studio, так что не надо ля-ля...

Копия из копии... Это не IAR листинг.
singlskv
Цитата(zltigo @ Apr 19 2009, 23:50) *
Копия из копии... Это не IAR листинг.
Все. Финиш sad.gif ©zligo


Уважаемый Супермодератор!
Всем конечно понятно Ваше желание быть истиной в последней инстанции во всех
топиках в которых Вы принимаете участие.
Но я Вам не советую спорить ради спора... иначе Вы рискуете стать посмешищем...
удар то Вы не очень готовы держать(отказываемся почему-то от тестов ... smile.gif )
Ну типа научитесь уже хоть иногда признавать что Ваша первая мысль была ошибочной...
Это очень Вам поможет...
zltigo
Цитата(singlskv @ Apr 19 2009, 23:16) *
Уважаемый Супермодератор!

Гогда я модератор, я так и подписываюсь. В остальных случаях, настоятельная просьба не навешивать ярлыки.
Цитата
Ну типа научитесь уже хоть иногда признавать что Ваша первая мысль была ошибочной...
Это очень Вам поможет...

В данном конкретном случае я просто не имею времени вычитывать нечто дизассемблированное представленное вместо IAR листинга.
Как не имею времени (и самое главное интереса по отношению к AVR) проделать этот хоть и простой зксперимент. То, что в AVR/IAR получение остатка от деления реализовано действительно громоздко, я увидел и запостил исходник. Пока для себя взял на заметку при реальной необходимости попробовать для AVR в реале.
singlskv
Цитата(zltigo @ Apr 20 2009, 00:29) *
В данном конкретном случае я просто не имею времени вычитывать нечто дизассемблированное представленное вместо IAR листинга.
Вы знаете, я то же немного программирую по работе иногда...
и если я участвую в форуме и в конкретных топиках высказываю свое мнение,
я обычно готов его подтвердить листингом или еще как-то... доступно...
Цитата
Как не имею времени (и самое главное интереса по отношению к AVR) проделать этот хоть и простой зксперимент. То, что в AVR/IAR получение остатка от деления реализовано действительно громоздко, я увидел и запостил исходник. Пока для себя взял на заметку при реальной необходимости попробовать для AVR в реале.
Как сказали бы Вы как модератор, это все очевидно и обсуждалось тысячу раз и
"Moderator:
Просьба не загромождать основные ветки (в частности "AVR") форума простейшими вопросами." smile.gif
zltigo
Цитата(singlskv @ Apr 19 2009, 23:45) *
"Moderator:
Просьба не загромождать основные ветки (в частности "AVR") форума простейшими вопросами." smile.gif

Вы не считаете первоначальный вопрос банальным?
Вы считаете, что первоначальный вопрос имеет хоть какое-то отношение к разделу AVR, куда его дважды запостил Автор?
Или на Вас просто слово "Модератор" действует, как красная тряпка?
P.S.
Moderator:
Вопросы риторические. Отвечать в форуме не надо. Если очень хочется - в личную почту. Ознакомлюсь по возврашению из командировки.
ARV
вот ведь спорить любители smile.gif я провел тест за вас:
Код
#include <avr/io.h>

volatile uint16_t result;
volatile uint32_t temp;

int main(void){

  while(1){
    PORTB = 1; // точка 1
    result = rand() % 10;
    
    PORTB = 0; // точка 2

    temp = rand() * 10UL;
    temp >>= 15;

    PORTB = 1; // точка 3
  }
}

target = atmega16, компилятор - WinAVR, среда - AVR Studio, сборка с оптимизацией по размеру кода (-Os)

методика теста: установка точек останова (помечены в комментариях) и замер числа тактов между точками 1 и 2 и между 2 и 3 соответственно.

результаты:
между 1 и 2: 1688 тактов
между 2 и 3: 1634 тактов

выигрыш далеко не десятикратный, речь вообще не идет о целых разах (выигрыш 3%) biggrin.gif в общем, результат был ожидаемым, как zltigo и "предчувствовал" smile.gif
singlskv
Цитата(ARV @ Apr 20 2009, 10:41) *
выигрыш далеко не десятикратный, речь вообще не идет о целых разах (выигрыш 3%) biggrin.gif в общем, результат был ожидаемым, как zltigo и "предчувствовал" smile.gif

а написать так не судьба :
Код
    temp = rand() * 20UL;
    temp >>= 16;

?
ARV
Цитата(singlskv @ Apr 20 2009, 12:07) *
а написать так не судьба :
Код
    temp = rand() * 20UL;
    temp >>= 16;
?
да в общем-то, что было ранее написано - то я и протестировал... но и этот вариант немногим лучше: 1688 и 1532 такта - выигрыш 9,2% - о разах речь просто не идет! а вот на счет распределения сомнения появляются...
singlskv
Цитата(ARV @ Apr 20 2009, 12:22) *
да в общем-то, что было ранее написано - то я и протестировал... но и этот вариант немногим лучше: 1688 и 1532 такта - выигрыш 9,2% - о разах речь просто не идет!
А теперь вычтите из каждого куска время работы rand(), тк нас сейчас интересует только эфективность %10
ARV
Цитата(singlskv @ Apr 20 2009, 12:25) *
А теперь вычтите из каждого куска время работы rand(), тк нас сейчас интересует только эфективность %10
прежде приведите доказательства, что при вашем методе не искажается равномерность распределения чисел... иначе смысла говорить дальше просто нет...
singlskv
Цитата(ARV @ Apr 20 2009, 12:26) *
прежде приведите доказательства, что при вашем методе не искажается равномерность распределения чисел... иначе смысла говорить дальше просто нет...
Ну мы просто поделили rand() на 3276,8 равномерность при этом явно не страдает, раз
она не страдала при % 10
mdmitry
Осталось только получить миллион нагенерированных значений и отдать на растерзание MATLABу с целью проверки статистики.
(В свое время искал генератор псевдослучайных чисел для AVR с более-менее равномерным распределением, проверял именно так.)
demiurg_spb
Цитата(singlskv @ Apr 20 2009, 12:35) *
Ну мы просто поделили rand() на 3276,8 равномерность при этом явно не страдает, раз она не страдала при % 10
Я считаю что не стоит сильно запрягаться по поводу равномерности и эквивалентности этих операций.
Тут интересна реальная разница в скорости. Т.к. N%10 используется ну очень и очень часто и безотносительно rand().
singlskv
Цитата(mdmitry @ Apr 20 2009, 13:58) *
Осталось только получить миллион нагенерированных значений и отдать на растерзание MATLABу с целью проверки статистики.
(В свое время искал генератор псевдослучайных чисел для AVR с более-менее равномерным распределением, проверял именно так.)

миллион лень было ждать
Код
#include <avr/io.h>
#include <stdlib.h>

volatile uint8_t result;
volatile uint32_t temp;
uint32_t M1[10],M2[10];

int main(void)
{
  uint16_t tmp16;
  uint32_t tmp32;
  uint32_t i;

  srand(1);
  for (i = 0; i < 200000; i++)
  {
    tmp16 = rand();
    result = tmp16 % 10;
    M1[result]++;    
  }

  srand(1);
  for (i = 0; i < 200000; i++)
  {
    tmp16 = rand();
    tmp32 = ((uint32_t)tmp16 << 2) + tmp16; // * 5
    tmp16 = tmp32 >> 8; // /256
    tmp16 <<= 2; // * 4
    result = tmp16 >> 8; // /256
    M2[result]++;
  }

  return 0;
}

Результат:
Код
     M1       M2
0  19829  20100
1  20131  19708
2  19867  20017
3  19951  19797
4  20045  20082
5  19890  20012
6  20095  20147
7  20420  20263
8  19648  20070
9  20124  19804

Как видно 2 способ дает лучшее распределение
Код
    result = tmp16 % 10;  <---  204  такта

Код
    tmp32 = ((uint32_t)tmp16 << 2) + tmp16; // * 5
    tmp16 = tmp32 >> 8; // /256
    tmp16 <<= 2; // * 4
    result = tmp16 >> 8; // /256
35 тактов
Итого: 204/35 =5,8 раз

Цитата(demiurg_spb @ Apr 20 2009, 15:56) *
Я считаю что не стоит сильно запрягаться по поводу равномерности и эквивалентности этих операций.
Тут интересна реальная разница в скорости. Т.к. N%10 используется ну очень и очень часто и безотносительно rand().
В данном случае мы берем разные "биты" из исходных 15бит от rand()
А %10 вроде уже неоднократно обсуждали
singlskv
А автору топика, если ему нужно только 0-9,и нужно быстро, стоит наверное остановиться на чем-то типа:
Код
volatile uint8_t result;
uint16_t s;

uint16_t irnd()
{
  return s = ((s * 0x3245) + 0x1B0D) & 0x7FFF;
}

int main(void)
{
  uint16_t tmp16;
  uint32_t tmp32;

  s = 1;
  tmp16 = irnd();
  tmp32 = ((uint32_t)tmp16 << 2) + tmp16;
  tmp16 = tmp32 >> 8;
  tmp16 <<= 2;
  result = tmp16 >> 8;

  return 0;
}
heburashka
мне просто нужно было от 0-9 причем времени вагон....

зато скока интерестного узнал rolleyes.gif
singlskv
Цитата(heburashka @ Apr 25 2009, 15:57) *
мне просто нужно было от 0-9 причем времени вагон....
зато скока интерестного узнал rolleyes.gif
Ну если бы Вы сразу сказали что времени у Вас вагон...
Спокойно бы спали, а теперь мысли-то куда девать ? ... smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.