Bash: Как сгенерировать случайное число с плавающей запятой с помощью $ RANDOM

Если диск не подключен через USB, рассмотрите возможность использования hdparm (версия> 9.31) для выполнения ATA Secure Erase диска. Эта команда заставляет микропрограмму накопителя стереть содержимое диска, включая плохие блоки.

Предупреждение: Используйте правильную букву диска - я показал в качестве примера / dev / sdX - не просто копируйте / вставляйте.

Во-первых, убедитесь, что он понимает команды ATA (большинство дисков, произведенных в последнее десятилетие или более, должны):

$ sudo hdparm -I /dev/sdX
.
# lots of other info here...
.
Security: 
    Master password revision code = 65534
        supported
    not enabled
    not locked
    not frozen
    not expired: security count
        supported: enhanced erase
    202min for SECURITY ERASE UNIT. 202min for ENHANCED SECURITY ERASE UNIT.

Последние две строки отрывка показывают, что он поддерживается.

Поэтому добавьте пароль к диску (очевидно, требование):

$sudo hdparm --user-master u --security-set-pass p /dev/sdX
security_password="p"

и удалите:

$sudo hdparm --user-master u --security-erase p /dev/sdX
security_password="p"

/dev/sdX:
Issuing SECURITY_ERASE command, password="p", user=user

Более подробная информация об этой процедуре доступна здесь .

5
18.02.2018, 03:24
6 ответов
awk -v n=10 -v seed="$RANDOM" 'BEGIN { srand(seed); for (i=0; i<n; ++i) printf("%.4f\n", rand()) }'

Esto generará nnúmeros aleatorios (diez en el ejemplo )en el rango [0,1 )con cuatro dígitos decimales. Utiliza la función rand()enawk(no en el estándar awkpero implementada por las implementaciones awkmás comunes )que devuelve un valor aleatorio en ese rango. El generador de números aleatorios está sembrado por la variable $RANDOMdel shell.

Cuando un programa awksolo tiene bloques BEGIN(y ningún otro bloque de código ), awkno intentará leer la entrada de su flujo de entrada estándar.

En cualquier sistema OpenBSD (o sistema que tenga la mismajotutilidad , originalmente en 4.2BSD ), lo siguiente generará 10 números aleatorios como se especifica:

jot -p 4 -r 10 0 1
11
27.01.2020, 20:31

Usar$(( ( RANDOM % N ) + MIN ))

Reemplace Ncon el número MAX y MIN con el número mínimo que desea generar.(Ncomo MAX es exclusivo, coloque N+1para tener MAX, MIN inclusive ).

O puede usar $(shuf -i MIN-MAX -n 1)en su lugar.

deman shuf:

-i, --input-range=LO-HI
    treat each number LO through HI as an input line
-n, --head-count=COUNT 
    output at most COUNT lines

El -n 1en shufaquí significa generar solo un número aleatorio.

Esto generará números aleatorios entre 0 ~9999 con ceros a la izquierda usandoprintf(como resultado, el número 1 es exclusivo ).

printf "0.%04d\n" $(( RANDOM % 1000 ))
0.0215
4
27.01.2020, 20:31

На баш

bc -l <<< "scale=4 ; $((RANDOM % 10000 ))/10000"

где 1/10000— ваша случайная точность, а 4— ваша выходная точность

1
27.01.2020, 20:31

Как указано в другом ответе, существуют и другие утилиты, которые можно использовать для генерации случайных чисел. В этом ответе я ограничиваю свои ресурсы $RANDOMи несколькими основными арифметическими функциями.

Для чисел с плавающей запятой попробуйте что-то вроде

printf '%s\n' $(echo "scale=8; $RANDOM/32768" | bc )

Это даст вам максимальную точность, потому что $RANDOMгенерирует только числа от 0 до 32767. (включая 32767! )Но я также нарушил правило использования базовых арифметических функций, вызвав bc.

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

Точность

Используя подход $RANDOM/32768, поскольку $RANDOMгенерирует значения от 0 до 32767, результатом $RANDOM/32768также будет конечное число значений. Другими словами, это по-прежнему дискретная случайная величина (, и с помощью компьютера вы никогда не сможете избежать этого факта ). Имея это в виду, вы можете достичь некоторой степени точности , используя printf.

Если вы хотите более тонкое покрытие интервала, вы можете начать думать с основанием 32768. Таким образом, теоретически $RANDOM + $RANDOM*32768должно дать вам равномерное распределение между 0 и 1 073 741 823. Но я сомневаюсь, что командная строка справится с такой точностью очень хорошо. Несколько моментов, касающихся этого конкретного случая:

  • Сумма двух независимых, равномерно распределенных случайных величин не всегда однородна. В этом случае, по крайней мере, теоретически (см. третий пункт ), они есть.
  • Не думайте, что можно упростить $RANDOM + $RANDOM*32768 = $RANDOM * ( 1 + 32768 ). Два появления $RANDOMна самом деле являются двумя разными событиями.
  • Я недостаточно знаю о том, как генерируется $RANDOM, чтобы знать, действительно ли двойной вызов этого метода сгенерирует два независимых случайных события.

Диапазон

Рассмотрим просто $RANDOM/32768. Если вам нужно число в диапазоне, скажем [a,b), затем

$RANDOM/32768*(b-a) + a

приведет вас в нужный диапазон.

Генерация целочисленных значений

Во-первых, рассмотрите возможность генерации случайных чисел между [0,b), где bменьше, чем 32768. Рассмотрим произведение q*b, где q— целая часть 32768/b. Тогда вы можете сгенерировать случайное число от 0 до 32767, но отбросить те, которые больше или равны q*b. Позвоните на сгенерированный таким образом номер G. Тогда Gпопадет в диапазон от 0 до q*b, и его распределение будет равномерным. Теперь примените модульную арифметику, чтобы уменьшить это значение до нужного диапазона :

.
G % b

Обратите внимание, случайным образом генерируется число следующим образом

$RANDOM % b

не создаст равномерного распределения, если только bне окажется одним из делителей 32768.

Написание bash-скрипта для этого

Вычисление q*bкак описано выше звучит как боль. Но на самом деле это не так. Вы можете получить его следующим образом:

q*b = 32768 - ( 32768 % b )

В Bash это можно сделать с помощью

$((32768 - $((32768 % b)) ))

Следующий код сгенерирует случайное число в диапазоне 0..b(, не включаяb).b=$1

m=$((32768 - $((32768 % $1)) ))
a=$RANDOM
while (( $a > $m )); 
do
    a=$RANDOM
done
a=$(($a % $1))
printf "$a\n"

Приложение

Технически нет смысла работать с

m=$((32768 - $((32768 % $1)) ))

Следующее сделает то же самое

a=$RANDOM
while (( $a > $1 )); 
do
    a=$RANDOM
done
printf "$a\n"

Это намного больше работы, но компьютеры работают быстро.

Генерация целого числа в большем диапазоне

Я дам вам разобраться. Необходимо соблюдать осторожность,и в какой-то момент вам придется принять во внимание ограничения памяти компьютера при выполнении арифметических операций.

Последнее примечание

Принятый ответ не будет создавать случайное число от 0 до 1.

Чтобы увидеть это, попробуйте следующее

$ for i in {1..1000}; do echo.$RANDOM; done | awk '{ a += $1 } END { print a }'

Для действительно равномерного распределения по [0,1)вы должны увидеть среднее значение, близкое к 0.500.

Но, как вы можете видеть, запустив приведенный выше фрагмент, вместо этого вы получите что-то вроде 314.432или 322.619. Поскольку это 1000 чисел, среднее значение равно .322. Истинное среднее значение для этой последовательности сгенерированных чисел равно.316362

Вы можете получить это истинное среднее значение с помощью скрипта perl

  perl -e '{ $i=0;  
             $s=0; 
             while ( $i<=32767 ) 
               { 
                 $j = sprintf "%.5f", ".$i"; 
                 $j =~ s/^0\.//; 
                 print "$j\n"; 
                 $s += $j; 
                 $i++ 
               }; 
             printf "%.5f\n", $s/32767; 
           }' 

Я добавляю сюда целые числа, чтобы помочь вам понять, почему такой подход с использованием .$RANDOMне делает того, что вы, скорее всего, хотите. Другими словами, подумайте о том, какие целые числа генерируются, а какие вообще отсутствуют. Пропускается довольно большое количество; довольно многие удваиваются.

10
27.01.2020, 20:31

zshимеет rand48()арифметическую функцию (оболочку стандартной функции erand48())в своем zsh/mathfuncмодуле:

zmodload zsh/mathfunc
printf '%.4f\n' $((rand48()))

В то время как $RANDOMявляется 15-битным, псевдо -случайным и воспроизводимым, bash5.1+ имеет более безопасное 32-битное целое число $SRANDOM, основанное на действительно случайных источниках, где они доступны. Он не поддерживает арифметику с плавающей запятой,но, по крайней мере, вы можете использовать его для заполнения псевдослучайного генератора awk(, который в противном случае по умолчанию использует очень предсказуемый результатtime()):

echo "$SRANDOM" | awk '
  {
    srand($1)
    for (i = 0; i < 20; i++)
      printf "%.4f\n", rand()
  }'

(имейте в виду, что это всего лишь 32 бита энтропии, и awkвыполняет детерминированную псевдо--случайную генерацию на основе этого начального числа)

1
27.01.2020, 20:31

В системах, где printf оболочки может понимать формат %a(bash ksh zsh и т. д. )и, следовательно, может выполнять внутреннее изменение базы (hex -> dec)(равномерный в [0,1)в диапазоне от 0,00003 до 0,99997):

printf '%.5f\n' "$(printf '0x0.%04xp1' $RANDOM)"

Вы даже можете использовать больше цифр, объединив больше вызовов на$RANDOM(от 0,000000001 до 0,999999999)

printf '%.9f\n'  "$(printf '0x0.%08xp2' $(( ($RANDOM<<15) + $RANDOM )))"

Внутренний (для оболочки )алгоритм "$RANDOM" основан на линейном -регистре сдвига с обратной связью (LFSR ). Это не криптографически безопасные генераторы псевдослучайных чисел (CSPRNG ). Лучшим вариантом является использование байтов из устройства /dev/urandom. Это потребует вызова внешнего восьмеричного или шестнадцатеричного дампа.

$ printf '%.19f\n' "0x0.$(od -N 8 -An -tx1 /dev/urandom | tr -d ' ')"
0.7532810412812978029

$ printf '%.19f\n' "0x0.$(hexdump -n 8 -v -e '"%02x"' /dev/urandom)"
0.9453460825607180595

Очень простое (, но не -единообразное )решение для получения числа с плавающей запятой:

printf '0.%04d\n' $RANDOM

Способ сделать его равномерным в диапазоне [0,1)(, не включающем 1):

while a=$RANDOM; ((a>29999)); do :; done; printf '0.%04d\n' "$((a%10000))"
7
27.01.2020, 20:31

Теги

Похожие вопросы