Last active
January 15, 2019 16:56
-
-
Save hyginn/af6e768e638355d50222f64e39816553 to your computer and use it in GitHub Desktop.
Full-range, quantum random integers in R from hexadecimals via the qrandom package
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# x2int.R | |
# | |
# Author: Boris Steipe (ORCID: 0000-0002-1134-6758) | |
# License: (c) Author (2018) + MIT | |
# Date: 2019-01-14 | |
# | |
# A utility to use qrandom::qrandom() to get integers from the full range | |
# of machine representable integers | |
# ==== intro =================================================================== | |
# I've been looking at the fabulous qrandom package (Köstlmeier 2019) that | |
# provides an interface to the equally fabulous quantum-randomness generator at | |
# ANU in Canberra. (https://qrng.anu.edu.au) (Haw at al. 2005) | |
if (!requireNamespace("qrandom")) { | |
install.packages(qrandom) | |
} | |
# ==== motivation ============================================================== | |
# I had planned to use qrandom() to get better seeds for R's RNG. R seeds the | |
# RNG once per session from Sys.time() and the process ID. That's a very small | |
# space of seeds! Moreover, random integers are produced from runif(), and | |
# multiplying an integer range with a floating point number. As Ottoboni and | |
# Stark recently showed (2018), that approach has sampling issues. So there is | |
# an incentive to do better and such improvement might go through working with | |
# true random numbers. Alas, set.seed() requires a signed 32-bit integer, and | |
# qrandom() doesn't supply those. Obviously we should be able to piece that | |
# together from hexadecimals. One would think. | |
# I was surprised to find that strtoi() does not work for negative numbers: | |
strtoi("0x7fffffff") # 2147483647 - same as .Machine$integer.max | |
# ... but the hex of -1 is "0xffffffff", and | |
strtoi("0xffffffff") # NA | |
# However, the inbuilt functions do work the other way around: | |
as.hexmode(-1) # [1] "ffffffff" | |
# ... which tells us that our representation was correct, but not how | |
# to obtain it. | |
# Unfortunately... | |
qrandom::qrandomunif(1, -.Machine$integer.max, .Machine$integer.max) | |
# gives an error, and the fabulous ANU quantum random server does not supply | |
# signed integers. (Looking under the hood of qrandomunif(), these numbers are | |
# indeed obtained by multiplying an R 32-bit floating point number with a | |
# disired output range.) | |
# ==== requirements and design ================================================= | |
# Time to code our own: | |
# Strategy: break up the 8 digit hex block into 4 two-digit blocks, | |
# convert these to bits, assemble them in the correct order, and | |
# reinterpret as a signed 32 bit integer, thus avoiding intermediate conversion | |
# to integers outside the range at all times. | |
# | |
# This required to understand how integers are represented in the machine in | |
# the first place. Shout out to Chua Hock-Chuan (2014), at NTU Singapore | |
# for a very helpful tutorial. | |
# https://www3.ntu.edu.sg/home/ehchua/programming/java/datarepresentation.html | |
# ==== code ==================================================================== | |
x2int <- function(x) { | |
# x: an 8 digit hex string | |
# return: its signed integer equivalent | |
stopifnot(all(nchar(x) == 8)) | |
x[x == "80000000"] <- "00000000" # input would underflow: "-0" | |
x2bit <- function(x) { | |
# x: an 8 digit hex string | |
# return: a 32 integer vector of [0, 1] as its binary representation | |
x4 <- substring(x, c(1, 3, 5, 7), c(2, 4, 6, 8)) | |
x4 <- rev(paste0("0x", x4)) | |
m4 <- sapply(x4, FUN = function(x) { intToBits(strtoi(x))[1:8] }) | |
return(as.integer(as.vector(m4))) | |
} | |
bit2int <- function(x) { | |
# x: a 32 integer vector of [0, 1] | |
# return: its signed integer equivalent | |
p2 <- 2^(0:30) # powers of two | |
s <- 1 # initialize sign | |
if (x[32] == 1) { # sign bit is set | |
x <- c(ifelse(x[1:31] == 1, 0, 1), x[32]) # flip bits | |
s <- -1 # sign is negative | |
} | |
return(as.integer((s * sum(x[1:31] * p2)) - x[32])) | |
} | |
int <- sapply(x, FUN = function(x) { bit2int(x2bit(x)) }, USE.NAMES = FALSE) | |
return(int) | |
} | |
# ==== examples ================================================================ | |
# 10 random integers | |
(x <- qrandom::qrandom(n = 10, type = "hex16", blocksize = 4)) | |
# [1] "3e1a0d73" "82116a50" "92e2b36c" "4ad988b0" "9e892b8f" | |
# [6] "5fcc564e" "59c29f0e" "dfbaa377" "b8348f8f" "ed8e7f53" | |
x2int(x) | |
# [1] 1041894771 -2112787888 -1830636692 1255770288 -1635177585 | |
# [6] 1607226958 1505926926 -541416585 -1204514929 -309428397 | |
# ==== tests =================================================================== | |
# Manual test - try anything interesting: | |
# x <- "d30124c6" | |
# x2int(x) # -754899770 | |
# as.hexmode(-754899770) # "d30124c6" | |
# | |
library(testthat) | |
test_that("conversions are correct", { | |
expect_equal(0, x2int("00000000")) | |
expect_equal(1, x2int("00000001")) | |
expect_equal(-1, x2int("ffffffff")) | |
expect_equal(.Machine$integer.max, x2int("7fffffff")) | |
expect_equal(0, x2int("80000000")) | |
expect_equal(-.Machine$integer.max, x2int("80000001")) | |
expect_equal(strtoi("0x12345678"), x2int("12345678")) | |
expect_equal(12345678, x2int("00bc614e")) | |
expect_equal(-12345678, x2int("ff439eb2")) | |
expect_equal(c(1, -1), x2int(c("00000001", "ffffffff"))) | |
expect_error(x2int(c("0001", "ffffffff"))) | |
}) | |
# ==== references ============================================================== | |
# Chua HC. (2014) A Tutorial on Data Representation. | |
# https://www3.ntu.edu.sg/home/ehchua/programming/java/datarepresentation.html | |
# J.Y. Haw, S.M. Assad, A.M. Lance, N.H.Y. Ng, V. Sharma, P.K. Lam, and T. Symul | |
# (2005) Maximization of Extractable Randomness in a Quantum Random-Number | |
# Generator. Phys. Rev. Applied 3, 054004 | |
# Köstlmeier, S (2019) qrandom: True Random Numbers using the ANU Quantum Random | |
# Numbers Server https://cran.r-project.org/package=qrandom | |
# Ottoboni, K and Stark, PB. (2018) Random problems with R. | |
# https://www.stat.berkeley.edu/~stark/Preprints/r-random-issues.pdf | |
# [END] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment