Почему возникает неожиданный результат в arc4random() % n?

у меня есть

for (int i = 0; i< 10; i++) {
    CGFloat longerA = ((arc4random() % 80) - 40) / 100.0f;
    NSLog(@"%f",longerA);
}

и результат

2013-09-20 11:41:30.801 ****[7025:a0b] 0.390000
2013-09-20 11:41:30.801 ****[7025:a0b] 0.080000
2013-09-20 11:41:30.801 ****[7025:a0b] 0.380000
2013-09-20 11:41:30.801 ****[7025:a0b] 42949672.000000
2013-09-20 11:41:30.802 ****[7025:a0b] 0.060000
2013-09-20 11:41:30.802 ****[7025:a0b] 0.080000
2013-09-20 11:41:30.802 ****[7025:a0b] 0.290000
2013-09-20 11:41:30.802 ****[7025:a0b] 42949672.000000
2013-09-20 11:41:30.803 ****[7025:a0b] 0.350000
2013-09-20 11:41:30.803 ****[7025:a0b] 0.180000

я просто не могу понять, почему есть результаты 42949672.000000

Пожалуйста, объясните мне, почему это происходит

Как я «понимаю», он должен принимать случайные (80) - 40 и результат / 100.0f, поэтому я просто не понимаю, как это (arc4random ()% 80) может быть больше 79.


person Some_single_man    schedule 20.09.2013    source источник


Ответы (2)


Документировано, что функция arc4random возвращает и u_int32_t. Это похоже на беззнаковый тип, поэтому, когда вы бросаете число ‹ 40, а затем вычитаете 40, вы получаете арифметику недолив. Вот откуда берется большое число (2 ^ 32 — что-то).

person zoul    schedule 20.09.2013
comment
Спасибо за ответ, я постараюсь получить его с этой точки сейчас. Я отмечу как отвеченный, когда я действительно получу это. - person Some_single_man; 20.09.2013
comment
Насколько я понимаю, у меня есть тип, который не поддерживает числа, равные ‹ 0, поэтому он выдает мне ошибку? когда результат ‹ 0? - person Some_single_man; 20.09.2013
comment
По сути, да. Прочтите что-нибудь о типах чисел со знаком и без знака, а также об арифметическом переполнении и потере значимости. - person zoul; 20.09.2013

arc4random возвращает целые числа без знака, которые не могут быть меньше 0. Вычитание 40 приведет к занижению значения и возврату к чему-то близкому к максимальному значению.

У вас также есть модуль смещения в вашей функции (некоторые значения будут более распространены, чем другие). Исправьте это, используя arc4random_uniform(80) вместо % 80. Таким образом, правильное решение:

for (int i = 0; i< 10; i++) {
    CGFloat longerA = (((int)arc4random_uniform(80)) - 40) / 100.0f;
    NSLog(@"%f",longerA);
}
person Hampus Nilsson    schedule 20.09.2013
comment
Спасибо за ответ, но я не люблю использовать приведения. Также я уже переделываю эту строку как CGFloat longA = (arc4random() % 80) / 100.0f - 0.4f; - person Some_single_man; 20.09.2013
comment
Тогда вы все еще сохраняете смещение по модулю. Значения от 0 до 16 будут вдвое больше, чем от 17 до 79. Используйте arc4random_uniform вместо % 80. - person Hampus Nilsson; 20.09.2013
comment
Я прочитал смещение по модулю. Но почему от 0 до 16 будет вдвое больше, чем от 17 до 79? Насколько я понимаю, у меня будут некоторые числа, которые будут иметь не 1/80, а 1/80 + some_really_small_value. Макс ранд в u_int32_t довольно большой. Но да, вы правы, я тоже должен избегать этой низкой возможности. - person Some_single_man; 20.09.2013