3

I need to generate some 64-bit signed integer for testing.

How can I do this?

#!/bin/sh
long=$(????)

4 Answers 4

4

Combine 2 32-bit integers captured from /dev/urandom. It should be possible to use od to capture a single 64-bit value per Stéphane's answer, but on at least some versions of OS X this fails without an appropriate error message.

#!/bin/sh
low32=$(od -An -td4 -N4 < /dev/urandom)
high32=$(od -An -td4 -N4 < /dev/urandom)
long=$(($low32 + ($high32 << 32) ))
4

macOS comes with Python. Use its random module.

python -c 'import random; rng = random.SystemRandom(); print rng.randint(-2**63, 2**63-1)'

If you don't need secure random numbers, this can be simplified to

python -c 'import random; print(random.randint(-2**63, 2**63-1))'
2

As macOS has /dev/urandom, you should be able to do:

od -An -vtd8 -N8 < /dev/urandom

However, according to those who've tried it on an actual macOS system (see comments), it doesn't work there. As macOS is meant to be a certified Unix system, that means it's a bug as POSIX clearly specifies the behaviour of that command. The only thing that POSIX leaves unspecified (implementation defined) is the byte order (which we don't care about here as that's all random bytes).

Alternatively, you could use ksh/bash/zsh's $RANDOM here. Even though macOS' sh is based on bash nowadays, it would be better to switch to bash/zsh (or ksh implementations other than mksh whose arithmetic use 32bits) as $RANDOM is not a sh feature so may not work in future version of macOS if they decide to switch to a different shell.

m=32768 # $RANDOM span
long=$((RANDOM+RANDOM*m+RANDOM*m*m+RANDOM*m*m*m+RANDOM*m*m*m*m))

or:

long=$((RANDOM|(RANDOM<<15)|(RANDOM<<30)|(RANDOM<<45)|(RANDOM<<60)))

That's 5*15 == 75 bits but that will be truncated to 64 bits by the shell.

In the POSIX tool chest, the way to generate random numbers is with awk's rand(), so you could do:

awk 'BEGIN{srand(); printf "%.20g\n", rand() * (2^64) - (2^63)}'

Beware though that with many awk implementations (those that base the srand() seed on the result of time(3)), you'll get the same output if you run it twice in the same second.

Also, because of the way floating point numbers are represented, I'd expect there would be some 64bit numbers (like 263-1) that it would never output.

9
  • The command doesn't appear to work as expected. Commented Dec 23, 2016 at 12:02
  • @ThomasDickey, in what way? It does work as expected on a GNU system, I don't have a macOS system to test it on, but it seems to me it should work on Unix compliant systems. Commented Dec 23, 2016 at 12:19
  • @StéphaneChazelas; I also see correct result on GNU/Linux. On MacOS, this appears to give a signed 8-bit value displayed as 32-bit (i.e., either between 0-127 or 4294967040-4294967295). Checking on OSX options for od... Commented Dec 23, 2016 at 12:47
  • @user4556274, looks like a bug. FreeBSD doesn't support byte counts greater than 4, but at least, it gives you an error when you try to use -td8 for instance. Commented Dec 23, 2016 at 13:01
  • @user4556274, FreeBSD also fails with an error for -tdL. What do you get on macOS? Commented Dec 23, 2016 at 13:04
-2

You can append two 32-bit numbers together, e.g.,

#!/bin/bash
printf '0x%04x%04x\n' $RANDOM $RANDOM
j=$(printf '16#%04x%04x' $RANDOM $RANDOM)
echo $j
echo $(($j))

Sample output

0x5e34562d 
16#7cf567f9
2096457721

This is one of many features originating in the Korn shell (ksh), copied to bash and zsh a few years later.

Per comment - you can append additional bits:

#!/bin/bash    
printf '0x%04x%04x\n' $RANDOM $RANDOM
foo=32767
printf '%016x\n' $((foo << 49))
printf '%016x\n' $((foo << 34))
printf '%016x\n' $((foo << 19))
printf '%016x\n' $((foo << 4))
printf '%016x\n' $((foo % 16))

printf '%016x\n' $((foo << 49 |
                   (foo << 34) |
                   (foo << 19) |
                   (foo << 4) |
                   (foo % 16)))
printf '%d\n'    $((foo << 49 |
                   (foo << 34) |
                   (foo << 19) |
                   (foo << 4) |
                   (foo % 16)))

Sample output:

0x3a1e1184     
fffe000000000000
0001fffc00000000
00000003fff80000
000000000007fff0
000000000000000f
ffffffffffffffff
-1
2
  • $RANDOM goes from 0 to 32767 though. That's 15 bits. The OP is asking for 64 bits and for signed integers. Commented Dec 23, 2016 at 11:55
  • Doing 04x04x like that for 2 15 bit numbers means bit 15 and 31 of that hex number will always be 0, so you won't cover all the 64 bit spectrum with that approach. Commented Dec 23, 2016 at 12:17

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.