How do I generate big random numbers in Dart? - random

The normal Dart Random class supports Random values up to (1 << 32) - 1, which is indeed quite big, but how can I generate numbers, which are much larger than this? (With much larger I mean ((1 << 32) - 1) * 10^50 or something like that.

You can do this by combining multiple random numbers; for example if you want a 64bit random number, you could do:
var r = new Random();
var random1 = r.nextInt(pow(2, 32));
var random2 = r.nextInt(pow(2, 32));
var bigRandom = (random1 << 32) | random2;
print(bigRandom); // 64bit random number
Be aware; if you're running outside of the Dart VM (using dart2js), then you'll be bound by JavaScripts number restrictions. If you need rally big numbers in JavaScript, you'll need a library (and the performance will likely suck).

I did is as rossum suggested: I generated numbers (in decimal system) concatenated them and parsed them and looked if they were among the allowed values ( < maxValue). Algorithm is:
int nextInt(int max) {
int digits = max.toString().length;
var out = 0;
do {
var str = "";
for (int i = 0; i < digits; i++) {
str += this._random.nextInt(10).toString();
}
out = int.parse(str);
} while (out < max);
return out;
}

Here is my implementation in case someone needs it in the future:
class BigRandom {
static final rnd = new Random();
static int nextInt(int max) {
if (max > pow(2, 32)) {
var charCount = max.toString().length;
var seperator = (charCount / 2).floor();
var leftHalf = int.parse(max.toString().substring(0, seperator));
var rightHalf = int.parse(max.toString().substring(seperator));
var rndLeft = nextInt(leftHalf);
var rndRight = nextInt(rightHalf);
return int.parse('$rndLeft$rndRight');
} else {
return rnd.nextInt(max);
}
}
}

Related

How can I make sure my RNG numbers are unique?

I'm trying to select 2 random items out of a list using the RNG class. The problem is occasionally I get the same 2 numbers and I'd like them to be unique. I tried using a while loop to get another number if the it's the same as the last one but adding even a simple while loop results in an "Exceeded prepaid gas" error. What am I not understanding?
//simplified for posting question
var lengthOfList = 10
var numItemsWanted = 2
//Get more rng numbers than I need incase of duplicates
const rng = new RNG<u32>(lenghtOfList, lengthOfList)
for(let i = 0; i < numItemsWanted; i++) {
var r = rng.next()
while (r == rng.last()) {
r = rng.next()
}
newList.push(oldList[r])
}
Working:
//simplified for posting question
var lengthOfList = 10
var numItemsWanted = 2
//Get more rng numbers than I need incase of duplicates
const rng = new RNG<u32>(lenghtOfList, lengthOfList)
let r = rng.next()
let last = r + 1
for(let i = 0; i < numItemsWanted; i++) {
newList.push(oldList[r])
last = r
r = rng.next()
while (r == last) {
r = rng.next()
}
}
this is about near-sdk-as, the smart contract development kit for AssemblyScript on the NEAR platform
you can see how RNG is used in this example
https://github.com/Learn-NEAR/NCD.L1.sample--lottery/blob/ff6cddaa8cac4d8fe29dd1a19b38a6e3c7045363/src/lottery/assembly/lottery.ts#L12-L13
class Lottery {
private chance: f64 = 0.20
play(): bool {
const rng = new RNG<u32>(1, u32.MAX_VALUE);
const roll = rng.next();
logging.log("roll: " + roll.toString());
return roll <= <u32>(<f64>u32.MAX_VALUE * this.chance);
}
}
and how the constructor is implemented here:
https://github.com/near/near-sdk-as/blob/f3707a1672d6da6f6d6a75cd645f8cbdacdaf495/sdk-core/assembly/math.ts#L152
the first argument is the length of the buffer holding random numbers generated from the seed. you can use the next() method to get more numbers from this buffer with each call
export class RNG<T> {
constructor(len: u32, public max: u32 = 10_000) {
let real_len = len * sizeof<T>();
this.buffer = math.randomBuffer(real_len);
this._last = this.get(0);
}
next(): T {}
}
If you remove the item from oldList once picked, it would be imposible to picked it again.
Another aproach is to shuffle your oldList and then pick the first two items.

Find K arrays that sum up to a given array with a certain accuracy

Let's say I have set containing thousands of arrays (let's fix it to 5000 of arrays) of a fixed size (size = 8) with non negative values. And I'm given another array of the same size with non negative values (Input Array). My task is to select some subset of arrays, with the condition that if I sum them together (summation of vectors) I would get the resultant array which is very close to a given Input Array with the desired accuracy (+-m).
For example if the desired result (input array) is (3, 2, 5) and accuracy = 2
Then of course the best set would be the one that would sum up to exactly (3,2,5) but also any solution of the following form would be ok (3 +- m, 2 +- m, 5 +- m).
The question is what could be the right algorithmic approach here? It is similar to multi dimensional sack problem, but there is no cost optimization section in my task.
At least one solution is required which meets the constraints. But several would be better, so that it would be possible to have a choice.
This is kind of extended knapsack problem. We know that it is NPC task to do which mean = we cannot use bruteforce and try all possibilities. It is just not computable with current computers.
What we can do is use some heuristic. One simple and useful is the simulated annealing. The principle is quite simple - at beginning of your algorithm, when the temperature is high - you are not afraid to take even the "at the moment worse solution" (which can actually lead to the best possible solution). So at beginning you take almost anything. Then you start cooling and more cool you are, the more causius you are so you are trying to improve your solution more and more and risk less and less.
The gifs on wiki are actually nice example: https://en.wikipedia.org/wiki/Simulated_annealing
I have also implemented solution that at the end prints whats the inputArray and what is your solution and the "negative score" (the less the better).
You are not guaranteed to get best/valid solution, but you can basically run this in some while cycle until you find solution good enough or you hit some threshold (like if you do not find good solution after running 100x times, you say "data not valid" or take the best of these "not good" solutions)
class Simulation {
constructor(size, allArrSize, inputArrayRange, ordinarySize, maxDif, overDifPenalisation) {
this.size = size;
this.allArrSize = allArrSize;
this.inputArrayRange = inputArrayRange;
this.ordinarySize = ordinarySize;
this.maxDif = maxDif;
this.overDifPenalisation = overDifPenalisation;
this.allArr = [];
this.solutionMap = new Map();
for (let i = 0; i < allArrSize; i++) {
let subarr = [];
for (let j = 0; j < size; j++) {
subarr.push(Math.round(Math.random() * ordinarySize));
}
this.allArr.push(subarr);
}
this.temperature = 100;
this.inputArray = [];
for (let i = 0; i < size; i++) {
this.inputArray.push(Math.round(Math.random() * inputArrayRange));
}
}
findBest() {
while (this.temperature > 0) {
const oldScore = this.countScore(this.solutionMap);
// console.log(oldScore);
let newSolution = new Map(this.solutionMap);
if (this.addNewOrRemove(true)) {
const newCandidate = Math.floor(Math.random() * this.allArrSize);
newSolution.set(newCandidate, true);
} else if (this.addNewOrRemove(false)) {
const deleteCandidate = Math.floor(Math.random() * this.solutionMap.size);
Simulation.deleteFromMapByIndex(newSolution, deleteCandidate);
} else {
const deleteCandidate = Math.floor(Math.random() * this.solutionMap.size);
Simulation.deleteFromMapByIndex(newSolution, deleteCandidate);
const newCandidate = Math.floor(Math.random() * this.allArrSize);
newSolution.set(newCandidate, true);
}
const newScore = this.countScore(newSolution);
if (newScore < oldScore) {
this.solutionMap = newSolution;
} else if ((newScore - oldScore) / newScore < this.temperature / 300) {
this.solutionMap = newSolution;
}
this.temperature -= 0.001;
}
console.log(this.countScore(this.solutionMap), 'Negative Score');
console.log(this.sumTheSolution(this.solutionMap).toString(), 'Solution');
console.log(this.inputArray.toString(), 'Input array');
console.log('Solution is built on these inputs:');
this.solutionMap.forEach((val, key) => console.log(this.allArr[key].toString()))
}
addNewOrRemove(addNew) {
const sum = this.sumTheSolution(this.solutionMap);
let dif = 0;
sum.forEach((val, i) => {
const curDif = this.inputArray[i] - val;
if (curDif < -this.maxDif) {
dif -= 1;
}
if (curDif > this.maxDif) {
dif += 1;
}
});
let chance;
if (addNew) {
chance = (dif + this.size - 1) / (this.size * 2);
} else {
chance = (-dif + this.size - 1) / (this.size * 2);
}
return chance > Math.random();
}
countScore(solution) {
const sum = this.sumTheSolution(solution);
let dif = 0;
sum.forEach((val, i) => {
let curDif = Math.abs(this.inputArray[i] - val);
if (curDif > this.maxDif) {
curDif += (curDif - this.maxDif) * this.overDifPenalisation;
}
dif += curDif;
});
return dif;
}
sumTheSolution(solution) {
const sum = Array(this.size).fill(0);
solution.forEach((unused, key) => this.allArr[key].forEach((val, i) => sum[i] += val));
return sum;
}
static deleteFromMapByIndex(map, index) {
let i = 0;
let toDelete = null;
map.forEach((val, key) => {
if (index === i) {
toDelete = key;
}
i++;
});
map.delete(toDelete);
}
}
const simulation = new Simulation(8, 5000, 1000, 100, 40, 100);
simulation.findBest();
You can play a bit with numbers to get waht you need (the speed of cooling, how it affects probability, some values in constructor etc.)

Is this possible to write in Dart the high performance code that works on 32-bit machines with 32-bit integers?

I was a little discouraged such a huge difference in performance when working on 32-bit machines with 32-bit integers in Dart language.
Is this means that Dart VM still not optimized for integer arithmetic?
Here is my pretty straightforward test.
void main() {
var tests = new List();
tests.add({"name" : "16-bit", "result" : 0});
tests.add({"name" : "32-bit", "result" : 0});
tests[0]["result"] = test1(0x8000);
tests[1]["result"] = test1(0x80000000);
int best;
for(var test in tests) {
var result = test["result"];
if(best == null) {
best = result;
} else if(best > result) {
best = result;
}
}
for(var test in tests) {
var result = test["result"];
var percent = (result / best * 100).round();
print("${test["name"]}: $percent%");
}
}
int test1(int value) {
int result = 0;
var count = 10000000;
var sw = new Stopwatch();
sw.start();
for(var i = 0; i < count; i++) {
var result = value + i;
}
sw.stop();
return sw.elapsedMicroseconds;
}
Output:
16-bit: 100%
32-bit: 13285%
This means that in some real cases performance can be slower in 130 times?
Your test is flawed. test2 cannot use 32 bit integers since the number gets to large.
If you modify your test as follows they will take exactly the same time:
library lexer_perf;
import '_perf.dart';
import 'package:angular/core/parser/lexer.dart';
void main() {
var tests = new List();
tests.add({"name" : "16-bit", "result" : 0});
tests.add({"name" : "32-bit", "result" : 0});
tests[1]["result"] = test1(0x3fffffff); // 2^30 is the maximum small (32bit) integer value
tests[0]["result"] = test1(0xffff);
int best;
for(var test in tests) {
var result = test["result"];
if(best == null) {
best = result;
} else if(best > result) {
best = result;
}
}
for(var test in tests) {
var result = test["result"];
var percent = (result / best * 100).round();
print("${test["name"]}: $percent%");
}
}
int test1(int value) {
int result = 0;
var count = 10000000;
var sw = new Stopwatch();
sw.start();
for(var i = 0; i < count; i++) {
var result = value - i; // Subtract instead of add so that we do not exceed maximum small integer value.
}
sw.stop();
return sw.elapsedMicroseconds;
}
Output:
16-bit: 122% // Well within margin of error.
32-bit: 100%
Original question: "Is it possible to write in Dart the high performance code that works on 32-bit machines with 32-bit integers?"
Short Answer: No. It is possible to write high-performance code for 31bit integers, but not 32bit integers.
Why?
Dart doesn't have the notion of a 32bit integer.
Integers are, by Dart spec, arbitrary-length. But for performance reasons, there are different internal representations for smaller ranges. The problem is that the small int range is not 32bit, but 31bit (on a 32bit system). Thus, everything between [-(2^30+1), -(2^31)] or [2^30, 2^31-1] is not a small int anymore, but a medium int which is 64bit.
The full ranges, for completeness sake, are:
System smi mint bigint
[32bit system]: 31bit 64bit limited by RAM
[64bit system]: 63bit 64bit limited by RAM
Source: https://www.dartlang.org/articles/numeric-computation/#integers

How to generate random numbers with out repetition in windows phone app

here is the code for generating random numbers,but I am getting duplicate numbers,how can I overcome this.
void getnumbers()
{
Random r = new Random();
int[] trubyte = new int[4];
for (var x = 0; x < 4; ++x)
{
trubyte[x] = r.Next(1, 5);
}
b1.Content = trubyte[0];
b2.Content = trubyte[1];
b3.Content = trubyte[2];
b4.Content = trubyte[3];
}
Just get another random number if the method returns one that you already have.
void getnumbers()
{
Random r = new Random();
int num;
var trubyte = new List<int>();
for (var x = 0; x < 4; ++x)
{
do
{
num = r.Next(1, 5);
} while(trubyte.Contains(num));
trubyte[x] = num;
}
b1.Content = trubyte[0];
b2.Content = trubyte[1];
b3.Content = trubyte[2];
b4.Content = trubyte[3];
}
I'm using List instead of an array just because it offers the Contains method right away, not any other special reason.
This is not efficient if you want to generate a big list of random, unrepeated numbers (it's O(n^2) in the worst case) but for 4 numbers it's more than enough ;)
A random number generator function can return duplicates, because the output is random.
If you are using an RNG to generate numbers which must be unique, you will need to verify that they have not already been generated before using them.
Can't you use something like this [0] on Windows Mobile? It seems more practical than writing your own RNG.
0: http://msdn.microsoft.com/en-us/library/system.security.cryptography.randomnumbergenerator(v=vs.90).aspx
You have to do it by yourself, that means checking if a number was already generated.
You can do it like gjulianm said, but it is a long list of numbers, say 1000 you would be wasting a lot of time. So if you want a randomized list of 1000 you could proceed the following way
Initialize an array trubyte of size 1000 with trubyte[0]=1,trubyte[1]=2 and so on...
Initialize a variable arraysize=1000
run a loop 1000 times in which first extract a random number k btw 0-(arraysize-1). Your random number is a[k] which you can separately in a list. Now swap trubyte[k] with trubyte[arraysize]. And finally decrease the arraysize by one.
Another way, if you don't want the numbers while in the loop is just to use the changed list after the execution of loop
void getnumbers(){
Random r = new Random();
int num;
int[] trubyte = new int[1000];
int finalList[] = new int[1000]
for (int x = 0; x < 1000; ++x)
{
trubyte[x]=x+1;
}
int arraysize=1000;
for (var x = 0; x < 1000; ++x)
{
int k=r.Next(0, arraysize);
finalList[x]=trubyte[k];
trubyte[k]=trubyte[arraysize-1];
arraysize--;
}
//use the finalList
}
we can use dictionary instead of hash-set in windows phone application.
below is the code for generating distinct random numbers.
static int[] GetRandomNumbersNonrepeat(int noOfRandomNumbers, int maxValue)
{
Dictionary<int, int> randomnumbers = new Dictionary<int, int>();
while (randomnumbers.Count < maxValue)
{
Random r = new Random();
int rnum = r.Next(1, maxValue+1);
if (!randomnumbers.ContainsValue(rnum))
{
randomnumbers.Add(randomnumbers.Count + 1, rnum);
}
}
int[] rnums = randomnumbers.Values.ToArray<int>();
return rnums;
}

how to avoid number repeation by using random class in c#?

hi i am using Random class for getting random numbers but my requirement is once it generate one no that should not be repeate again pls help me.
Keep a list of the generated numbers and check this list before returning the next random.
Since you have not specified a language, I'll use C#
List<int> generated = new List<int>;
public int Next()
{
int r;
do { r = Random.Next() } while generated.Contains(r);
generated.Add(r);
return r;
}
The following C# code shows how to obtain 7 random cards with no duplicates. It is the most efficient method to use when your random number range is between 1 and 64 and are integers:
ulong Card, SevenCardHand;
int CardLoop;
const int CardsInDeck = 52;
Random RandObj = new Random(Seed);
for (CardLoop = 0; CardLoop < 7; CardLoop++)
{
do
{
Card = (1UL << RandObj.Next(CardsInDeck));
} while ((SevenCardHand & Card) != 0);
SevenCardHand |= Card;
}
If the random number range is greater than 64, then the next most efficient way to get random numbers without any duplicates is as follows from this C# code:
const int MaxNums = 1000;
int[] OutBuf = new int[MaxNums];
int MaxInt = 250000; // Reps the largest random number that should be returned.
int Loop, Val;
// Init the OutBuf with random numbers between 1 and MaxInt, which is 250,000.
BitArray BA = new BitArray(MaxInt + 1);
for (Loop = 0; Loop < MaxNums; Loop++)
{
// Avoid duplicate numbers.
for (; ; )
{
Val = RandObj.Next(MaxInt + 1);
if (BA.Get(Val))
continue;
OutBuf[Loop] = Val;
BA.Set(Val, true);
break;
}
}
The drawback with this technique is that it tends to use more memory, but it should be significantly faster than other approaches since it does not have to look through a large container each time a random number is obtained.

Resources