My Random Number Generator is producing small numbers - random

I'm trying to create a "random" number generator for my online game.
I want to create the number purely based on positions and stats of players, and also based on a small counter that increments by 1 each step in my controller.
Here's my code to create a "seed" and another function to use the seed to generate a random number from 0 -> max non-inclusive:
function generate_seed(){
var num = 1;
for(var i = 0; i < number_of_players; i++){
var prevNum = num;
num++;
}
num+=obj_controller.randStep; //randStep is a variable that gets incremented by 1 in my controller object each step
//Loops through all players
with(obj_player){
if(x % 2){num+=x;}
else {num-=x;}
if(y % 2){num+=y;}
else {num-=y;}
if(hp % 2){num+=hp;}
else {num-=hp;}
if(randStep % 2){num+=randStep;}
else {num-=randStep;}
}
return abs(num);
}
function random(var max){
//Generate synced random number from 0 -> max, does not include max
var seeder = synced_random_generate();
seeder+= max * 5; //Make sure the seed is greater than max
return seeder mod max;
}
The thing is, this sort of works, but if I do:
random(20000);
It will usually return a fairly small number relative to the max (20,000).
I've never seen it return a number greater than 3000. Which is very strange.
Does anyone know what's wrong or a possible simpler way to generate a random number based on player positions/stats and an incrementing counter in my controller?

Found a really great solution online:
int rand1(int lim)
{
static long a = 100001;
a = (a * 125) % 2796203;
return ((a % lim) + 1);
}

Related

Generate an array of numbers without duplicate in Solidity

I am building a Lottery Smart Contract in which user can buy a Ticket that have 5 generated numbers from 1 to 25 without duplicates numbers.
Everything works just fine, except that 30% of the time, Metamask says "transaction runs out of gas", because of this function.
The function below generate an array of 5 numbers between 1 and 25 :
/// #dev Generate 5 numbers ( 1 <= x >= 25) without duplicate numbers
/// #param _lotteryCount used for the random generator number function
/// #return uint256[5] return an array of 5 generated uint
function generateRandomTicketNumbers(uint256 _lotteryCount) internal view returns (uint8[5] memory) {
uint8[5] memory numbers;
uint256 generatedNumber;
// Execute 5 times (to generate 5 numbers)
for (uint256 i = 0; i < 5; i++) {
// Check duplicate
bool readyToAdd = false;
uint256 maxRetry = 5;
uint256 retry = 0;
// Generate a new number while it is a duplicate, up to 5 times (to prevent errors and infinite loops)
while (!readyToAdd && retry <= maxRetry) {
generatedNumber = (uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp, i, retry, _lotteryCount))) % 25).add(1);
bool isDuplicate = false;
// Look in all already generated numbers array if the new generated number is already there.
for (uint256 j = 0; j < numbers.length; j++) {
if (numbers[j] == generatedNumber) {
isDuplicate = true;
break;
}
}
readyToAdd = !isDuplicate;
retry++;
}
// Throw if we hit maximum retry : generated a duplicate 5 times in a row.
require(retry < maxRetry, 'Error generating random ticket numbers. Max retry.');
numbers[i] = uint8(generatedNumber);
}
return numbers;
}
I'm not sure to understand how Metamask estimates the gas of a transaction but I guess it runs locally the transaction, see how much gas it used, and use this amount for the real transaction.
If this is correct, that could explain why it fails 30% of the time. Sometime, this function needs to retry multiple times to generate a number in the "while" loop, and sometime, the "while" loop is only executed once.
I could force the function to runs every "for" and "while" loop the maximum number of time, but I believe there is a better solution than wasting gas.
Do you have any idea how I can fix this ?
Thanks !
First use chainlink as a source of randomness https://docs.chain.link/docs/chainlink-vrf/ , follow the best practices sections https://docs.chain.link/docs/chainlink-vrf-best-practices/ , then when you get the random number you can do as they recommend in the docs
function expand(
uint256 randomValue,
uint256 n
) public pure returns (uint256[] memory expandedValues) {
expandedValues = new uint256[](n);
for (uint256 i = 0; i < n; i++) {
expandedValues[i] = uint256(keccak256(abi.encode(randomValue, i)));
}
return expandedValues;
}

Constraint to generate random integers

I have some array of integers that I generate randomly for example between 0 and 9.
I have a set of constraints that I need to apply to this generation.
For example :
1) Constraint 1 -> the numbers at even position in the array should be 0 or 1.
2) Constraint 2 -> the array should have at least one 0 and at least one 1 on even values
etc ...
What I do for now :
I generate randomly the numbers array.
Then for each even position, I randomly pick between 0 and 1.
Then I check that for each even value, I have at least one 0 and at least one 1. If not, I regerate all the values with the constraint above (Then for each even position, I randomly pick between 0 and 1.) until I have something which works (in a do for).
However, this works good because these are very simple constraints.
3) Constraint 3 -> the sum of the differences between the numbers should be superior to a certain value.
etc ...
The issue I have is that it is inter dependent constraints problems and I dont want to encapsulate do while in another do while, etc ... when I add one constraint.
What would be the proper way to achieve this in the cleanest way possible?
Edit:
I realized I was not clear at all... My apologies.
I edited the constraints to make it easier to understand.
My code looks like that (typed on notepad++ might be mistakes) :
std::vector<int> myVector;
int N = 100; // vector contains 100 values
do{
myVector.clear();
for(int i=0;i<N;i++){
if(i%2==0){
myVector.push_back(rand() % 2);
}
else{
myVector.push_back(rand() % 10);
}
}
}while(!doesContains0and1(myVector));
bool MyClass::doesContains0and1(std::vector<int> avector)
{
bool returnVal = true;
for(int i=0;i<avector.size;i++){
if(i%2==0){
if(!avector.contains(0) || !avector.contains(1){
returnVal = false;
}
}
}
return returnVal;
}
The 3) constraint means, if I have for example :
0 5 1 7 0 9 0 1 1
that there is a constraint on abs(5-0) + abs (1-5) + abs(7-1) + ... etc > a certain value
These constraints are examples, I am more looking for some methodology than pure code :)
Thanks for your help !
Let me take a stab at this...
int sum;
for (int i = 0 ; i < array_size ; i++){
if (!(i % 10)) sum = 0; // resets the sum to 0
if(i % 2){ //even or odd
//odd
sum += array[i] = rand() % 2; // 1 or 0
if ((!(i % 10)) && (sum == 0 || sum == 5))
array[i] = sum?0:1;
}else{
//even
array[i] = rand();
}
}
This follows the first 2 constraints. The sum will count the number of 1's in each subset of 10. All 0's will yield a sum of 0 and all 1's will yield a sum of 5. It will set the last element accordingly.
I'm not sure how to interpret the 3rd constraint, but hopefully this gets you started

Random number with no repetition

What I am trying to do is make it so that the game I am creating will randomly change characters every 5 seconds.
I got this working via a timer, the only problem is I don't want them repeating, I'm currently working on dummy code so it's just changing the screen colour, but how can I make it so that it doesn't repeat the number it just called?
if (timer <= 0)
{
num = rand.Next(2);
timer = 5.0f;
}
That is the current code and then in the draw I've literally just done "if num equals a certain number then change background colour".
I tried adding a prev_num checker but I can't get it to work properly (here it is)
if (timer <= 0)
{
prev_number = num;
num = rand.Next(2);
if (prev_number == num)
{
num = rand.Next(2);
}
else
{
timer = 5.0f;
}
}
Consider that if you're picking (for example) a random number from 1-5 then there are five possible outcomes, so you would use rand.Next(5) to select the zero-based "ordinal" or index of the outcome, then convert it into the range you actually want (in this case, by adding one).
If you want a random number from 0-4, excluding the number you just picked, then there are only four possible outcomes, not five - if the previous number was 3, then the possible outcomes are 0, 1, 2 or 4. You can then simplify your algorithm by choosing one of those four outcomes (rand.Next(4)) and mapping that ordinal to your desired range. A simple mapping would be to say if the new random number is below the previous number, return it as-is, otherwise (if equal or greater) add one.
int new_num = rand.Next(4);
if(new_num >= prev_num)
{
new_num++;
}
Your new number is now guaranteed to be in the same range as the previous number, but not equal to it.
Maybe just put it into a loop instead of a single check?
Also, I think because your timer was inside the else then it was not always
updated correctly.
if (timer <= 0)
{
tempNum = rand.Next(2);
do
{
tempNum = rand.Next(2);
}
while (tempNum == num)
num = tempNum;
timer = 5.0f;
}
Create an array of sequential numbers and then shuffle them (like a deck of cards) when your application begins.
int[] numbers = new int[100];
for(int i = 0; i < numbers.Length; i++)
numbers[i] = i;
Shuffle(numbers);
Using a function to shuffle the list:
public static void Shuffle<T>(IList<T> list)
{
Random rng = new Random();
int n = list.Count;
while (n > 1) {
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
You can then access them sequentially out of the list. They will be random as the list was shuffled, but you won't have any repetitions since each number only exists once in the list.
if (timer <= 0)
{
num = numbers[index];
index++;
timer = 5.0f;
}

Finding the number of digits of an integer

What is the best method to find the number of digits of a positive integer?
I have found this 3 basic methods:
conversion to string
String s = new Integer(t).toString();
int len = s.length();
for loop
for(long long int temp = number; temp >= 1;)
{
temp/=10;
decimalPlaces++;
}
logaritmic calculation
digits = floor( log10( number ) ) + 1;
where you can calculate log10(x) = ln(x) / ln(10) in most languages.
First I thought the string method is the dirtiest one but the more I think about it the more I think it's the fastest way. Or is it?
There's always this method:
n = 1;
if ( i >= 100000000 ) { n += 8; i /= 100000000; }
if ( i >= 10000 ) { n += 4; i /= 10000; }
if ( i >= 100 ) { n += 2; i /= 100; }
if ( i >= 10 ) { n += 1; }
Well the correct answer would be to measure it - but you should be able to make a guess about the number of CPU steps involved in converting strings and going through them looking for an end marker
Then think how many FPU operations/s your processor can do and how easy it is to calculate a single log.
edit: wasting some more time on a monday morning :-)
String s = new Integer(t).toString();
int len = s.length();
One of the problems with high level languages is guessing how much work the system is doing behind the scenes of an apparently simple statement. Mandatory Joel link
This statement involves allocating memory for a string, and possibly a couple of temporary copies of a string. It must parse the integer and copy the digits of it into a string, possibly having to reallocate and move the existing memory if the number is large. It might have to check a bunch of locale settings to decide if your country uses "," or ".", it might have to do a bunch of unicode conversions.
Then finding the length has to scan the entire string, again considering unicode and any local specific settings such as - are you in a right->left language?.
Alternatively:
digits = floor( log10( number ) ) + 1;
Just because this would be harder for you to do on paper doesn't mean it's hard for a computer! In fact a good rule in high performance computing seems to have been - if something is hard for a human (fluid dynamics, 3d rendering) it's easy for a computer, and if it's easy for a human (face recognition, detecting a voice in a noisy room) it's hard for a computer!
You can generally assume that the builtin maths functions log/sin/cos etc - have been an important part of computer design for 50years. So even if they don't map directly into a hardware function in the FPU you can bet that the alternative implementation is pretty efficient.
I don't know, and the answer may well be different depending on how your individual language is implemented.
So, stress test it! Implement all three solutions. Run them on 1 through 1,000,000 (or some other huge set of numbers that's representative of the numbers the solution will be running against) and time how long each of them takes.
Pit your solutions against one another and let them fight it out. Like intellectual gladiators. Three algorithms enter! One algorithm leaves!
Test conditions
Decimal numeral system
Positive integers
Up to 10 digits
Language: ActionScript 3
Results
digits: [1,10],
no. of runs: 1,000,000
random sample: 8777509,40442298,477894,329950,513,91751410,313,3159,131309,2
result: 7,8,6,6,3,8,3,4,6,1
CONVERSION TO STRING: 724ms
LOGARITMIC CALCULATION: 349ms
DIV 10 ITERATION: 229ms
MANUAL CONDITIONING: 136ms
Note: Author refrains from making any conclusions for numbers with more than 10 digits.
Script
package {
import flash.display.MovieClip;
import flash.utils.getTimer;
/**
* #author Daniel
*/
public class Digits extends MovieClip {
private const NUMBERS : uint = 1000000;
private const DIGITS : uint = 10;
private var numbers : Array;
private var digits : Array;
public function Digits() {
// ************* NUMBERS *************
numbers = [];
for (var i : int = 0; i < NUMBERS; i++) {
var number : Number = Math.floor(Math.pow(10, Math.random()*DIGITS));
numbers.push(number);
}
trace('Max digits: ' + DIGITS + ', count of numbers: ' + NUMBERS);
trace('sample: ' + numbers.slice(0, 10));
// ************* CONVERSION TO STRING *************
digits = [];
var time : Number = getTimer();
for (var i : int = 0; i < numbers.length; i++) {
digits.push(String(numbers[i]).length);
}
trace('\nCONVERSION TO STRING - time: ' + (getTimer() - time));
trace('sample: ' + digits.slice(0, 10));
// ************* LOGARITMIC CALCULATION *************
digits = [];
time = getTimer();
for (var i : int = 0; i < numbers.length; i++) {
digits.push(Math.floor( Math.log( numbers[i] ) / Math.log(10) ) + 1);
}
trace('\nLOGARITMIC CALCULATION - time: ' + (getTimer() - time));
trace('sample: ' + digits.slice(0, 10));
// ************* DIV 10 ITERATION *************
digits = [];
time = getTimer();
var digit : uint = 0;
for (var i : int = 0; i < numbers.length; i++) {
digit = 0;
for(var temp : Number = numbers[i]; temp >= 1;)
{
temp/=10;
digit++;
}
digits.push(digit);
}
trace('\nDIV 10 ITERATION - time: ' + (getTimer() - time));
trace('sample: ' + digits.slice(0, 10));
// ************* MANUAL CONDITIONING *************
digits = [];
time = getTimer();
var digit : uint;
for (var i : int = 0; i < numbers.length; i++) {
var number : Number = numbers[i];
if (number < 10) digit = 1;
else if (number < 100) digit = 2;
else if (number < 1000) digit = 3;
else if (number < 10000) digit = 4;
else if (number < 100000) digit = 5;
else if (number < 1000000) digit = 6;
else if (number < 10000000) digit = 7;
else if (number < 100000000) digit = 8;
else if (number < 1000000000) digit = 9;
else if (number < 10000000000) digit = 10;
digits.push(digit);
}
trace('\nMANUAL CONDITIONING: ' + (getTimer() - time));
trace('sample: ' + digits.slice(0, 10));
}
}
}
This algorithm might be good also, assuming that:
Number is integer and binary encoded (<< operation is cheap)
We don't known number boundaries
var num = 123456789L;
var len = 0;
var tmp = 1L;
while(tmp < num)
{
len++;
tmp = (tmp << 3) + (tmp << 1);
}
This algorithm, should have speed comparable to for-loop (2) provided, but a bit faster due to (2 bit-shifts, add and subtract, instead of division).
As for Log10 algorithm, it will give you only approximate answer (that is close to real, but still), since analytic formula for computing Log function have infinite loop and can't be calculated precisely Wiki.
Use the simplest solution in whatever programming language you're using. I can't think of a case where counting digits in an integer would be the bottleneck in any (useful) program.
C, C++:
char buffer[32];
int length = sprintf(buffer, "%ld", (long)123456789);
Haskell:
len = (length . show) 123456789
JavaScript:
length = String(123456789).length;
PHP:
$length = strlen(123456789);
Visual Basic (untested):
length = Len(str(123456789)) - 1
conversion to string: This will have to iterate through each digit, find the character that maps to the current digit, add a character to a collection of characters. Then get the length of the resulting String object. Will run in O(n) for n=#digits.
for-loop: will perform 2 mathematical operation: dividing the number by 10 and incrementing a counter. Will run in O(n) for n=#digits.
logarithmic: Will call log10 and floor, and add 1. Looks like O(1) but I'm not really sure how fast the log10 or floor functions are. My knowledge of this sort of things has atrophied with lack of use so there could be hidden complexity in these functions.
So I guess it comes down to: is looking up digit mappings faster than multiple mathematical operations or whatever is happening in log10? The answer will probably vary. There could be platforms where the character mapping is faster, and others where doing the calculations is faster. Also to keep in mind is that the first method will creats a new String object that only exists for the purpose of getting the length. This will probably use more memory than the other two methods, but it may or may not matter.
You can obviously eliminate the method 1 from the competition, because the atoi/toString algorithm it uses would be similar to method 2.
Method 3's speed depends on whether the code is being compiled for a system whose instruction set includes log base 10.
For very large integers, the log method is much faster. For instance, with a 2491327 digit number (the 11920928th Fibonacci number, if you care), Python takes several minutes to execute the divide-by-10 algorithm, and milliseconds to execute 1+floor(log(n,10)).
import math
def numdigits(n):
return ( int(math.floor(math.log10(n))) + 1 )
Regarding the three methods you propose for "determining the number of digits necessary to represent a given number in a given base", I don't like any of them, actually; I prefer the method I give below instead.
Re your method #1 (strings): Anything involving converting back-and-forth between strings and numbers is usually very slow.
Re your method #2 (temp/=10): This is fatally flawed because it assumes that x/10 always means "x divided by 10". But in many programming languages (eg: C, C++), if "x" is an integer type, then "x/10" means "integer division", which isn't the same thing as floating-point division, and it introduces round-off errors at every iteration, and they accumulate in a recursive formula such as your solution #2 uses.
Re your method #3 (logs): it's buggy for large numbers (at least in C, and probably other languages as well), because floating-point data types tend not to be as precise as 64-bit integers.
Hence I dislike all 3 of those methods: #1 works but is slow, #2 is broken, and #3 is buggy for large numbers. Instead, I prefer this, which works for numbers from 0 up to about 18.44 quintillion:
unsigned NumberOfDigits (uint64_t Number, unsigned Base)
{
unsigned Digits = 1;
uint64_t Power = 1;
while ( Number / Power >= Base )
{
++Digits;
Power *= Base;
}
return Digits;
}
Keep it simple:
long long int a = 223452355415634664;
int x;
for (x = 1; a >= 10; x++)
{
a = a / 10;
}
printf("%d", x);
You can use a recursive solution instead of a loop, but somehow similar:
#tailrec
def digits (i: Long, carry: Int=1) : Int = if (i < 10) carry else digits (i/10, carry+1)
digits (8345012978643L)
With longs, the picture might change - measure small and long numbers independently against different algorithms, and pick the appropriate one, depending on your typical input. :)
Of course nothing beats a switch:
switch (x) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: return 1;
case 10: case 11: // ...
case 99: return 2;
case 100: // you get the point :)
default: return 10; // switch only over int
}
except a plain-o-array:
int [] size = {1,1,1,1,1,1,1,1,1,2,2,2,2,2,... };
int x = 234561798;
return size [x];
Some people will tell you to optimize the code-size, but yaknow, premature optimization ...
log(x,n)-mod(log(x,n),1)+1
Where x is a the base and n is the number.
Here is the measurement in Swift 4.
Algorithms code:
extension Int {
var numberOfDigits0: Int {
var currentNumber = self
var n = 1
if (currentNumber >= 100000000) {
n += 8
currentNumber /= 100000000
}
if (currentNumber >= 10000) {
n += 4
currentNumber /= 10000
}
if (currentNumber >= 100) {
n += 2
currentNumber /= 100
}
if (currentNumber >= 10) {
n += 1
}
return n
}
var numberOfDigits1: Int {
return String(self).count
}
var numberOfDigits2: Int {
var n = 1
var currentNumber = self
while currentNumber > 9 {
n += 1
currentNumber /= 10
}
return n
}
}
Measurement code:
var timeInterval0 = Date()
for i in 0...10000 {
i.numberOfDigits0
}
print("timeInterval0: \(Date().timeIntervalSince(timeInterval0))")
var timeInterval1 = Date()
for i in 0...10000 {
i.numberOfDigits1
}
print("timeInterval1: \(Date().timeIntervalSince(timeInterval1))")
var timeInterval2 = Date()
for i in 0...10000 {
i.numberOfDigits2
}
print("timeInterval2: \(Date().timeIntervalSince(timeInterval2))")
Output
timeInterval0: 1.92149806022644
timeInterval1: 0.557608008384705
timeInterval2: 2.83262193202972
On this measurement basis String conversion is the best option for the Swift language.
I was curious after seeing #daniel.sedlacek results so I did some testing using Swift for numbers having more than 10 digits. I ran the following script in the playground.
let base = [Double(100090000000), Double(100050000), Double(100050000), Double(100000200)]
var rar = [Double]()
for i in 1...10 {
for d in base {
let v = d*Double(arc4random_uniform(UInt32(1000000000)))
rar.append(v*Double(arc4random_uniform(UInt32(1000000000))))
rar.append(Double(1)*pow(1,Double(i)))
}
}
print(rar)
var timeInterval = NSDate().timeIntervalSince1970
for d in rar {
floor(log10(d))
}
var newTimeInterval = NSDate().timeIntervalSince1970
print(newTimeInterval-timeInterval)
timeInterval = NSDate().timeIntervalSince1970
for d in rar {
var c = d
while c > 10 {
c = c/10
}
}
newTimeInterval = NSDate().timeIntervalSince1970
print(newTimeInterval-timeInterval)
Results of 80 elements
0.105069875717163 for floor(log10(x))
0.867973804473877 for div 10 iterations
Adding one more approach to many of the already mentioned approaches.
The idea is to use binarySearch on an array containing the range of integers based on the digits of the int data type.
The signature of Java Arrays class binarySearch is :
binarySearch(dataType[] array, dataType key) which returns the index of the search key, if it is contained in the array; otherwise, (-(insertion point) – 1).
The insertion point is defined as the point at which the key would be inserted into the array.
Below is the implementation:
static int [] digits = {9,99,999,9999,99999,999999,9999999,99999999,999999999,Integer.MAX_VALUE};
static int digitsCounter(int N)
{
int digitCount = Arrays.binarySearch(digits , N<0 ? -N:N);
return 1 + (digitCount < 0 ? ~digitCount : digitCount);
}
Please note that the above approach only works for : Integer.MIN_VALUE <= N <= Integer.MAX_VALUE, but can be easily extended for Long data type by adding more values to the digits array.
For example,
I) for N = 555, digitCount = Arrays.binarySearch(digits , 555) returns -3 (-(2)-1) as it's not present in the array but is supposed to be inserted at point 2 between 9 & 99 like [9, 55, 99].
As the index we got is negative we need to take the bitwise compliment of the result.
At last, we need to add 1 to the result to get the actual number of digits in the number N.
In Swift 5.x, you get the number of digit in integer as below :
Convert to string and then count number of character in string
let nums = [1, 7892, 78, 92, 90]
for i in nums {
let ch = String(describing: i)
print(ch.count)
}
Calculating the number of digits in integer using loop
var digitCount = 0
for i in nums {
var tmp = i
while tmp >= 1 {
tmp /= 10
digitCount += 1
}
print(digitCount)
}
let numDigits num =
let num = abs(num)
let rec numDigitsInner num =
match num with
| num when num < 10 -> 1
| _ -> 1 + numDigitsInner (num / 10)
numDigitsInner num
F# Version, without casting to a string.

How do I find the nearest prime number?

Is there any nice algorithm to find the nearest prime number to a given real number? I only need to search within the first 100 primes or so.
At present, I've a bunch of prime numbers stored in an array and I'm checking the difference one number at a time (O(n)?).
Rather than a sorted list of primes, given the relatively small range targetted, have an array indexed by all the odd numbers in the range (you know there are no even primes except the special case of 2) and containing the closest prime. Finding the solution becomes O(1) time-wise.
I think the 100th prime is circa 541. an array of 270 [small] ints is all that is needed.
This approach is particularly valid, given the relative high density of primes (in particular relative to odd numbers), in the range below 1,000. (As this affects the size of a binary tree)
If you only need to search in the first 100 primes or so, just create a sorted table of those primes, and do a binary search. This will either get you to one prime number, or a spot between two, and you check which of those is closer.
Edit: Given the distribution of primes in that range, you could probably speed things up (a tiny bit) by using an interpolation search -- instead of always starting at the middle of the table, use linear interpolation to guess at a more accurate starting point. The 100th prime number should be somewhere around 250 or so (at a guess -- I haven't checked), so if (for example) you wanted the one closest to 50, you'd start about 1/5th of the way into the array instead of halfway. You can pretty much treat the primes as starting at 1, so just divide the number you want by the largest in your range to get a guess at the starting point.
Answers so far are rather complicated, given the task in hand. The first hundred primes are all less then 600. I would create an array of size 600 and place in each the value of the nearest prime to that number. Then, given a number to test, I would round it both up and down using the floor and ceil functions to get one or two candidate answers. A simple comparison with the distances to these numbers will give you a very fast answer.
The simplest approach would be to store the primes in a sorted list and modify your algorithm to do a binary search.
The standard binary search algorithm would return null for a miss, but it should be straight-forward to modify it for your purposes.
The fastest algorithm? Create a lookup table with p[100]=541 elements and return the result for floor(x), with special logic for x on [2,3]. That would be O(1).
You should sort your number in array then you can use binary search. This algorithm is O(log n) performance in worst case.
public static boolean p(int n){
for(int i=3;i*i<=n;i+=2) {
if(n%i==0)
return false;
}
return n%2==0? false: true; }
public static void main(String args[]){
String n="0";
int x = Integer.parseInt(n);
int z=x;
int a=0;
int i=1;
while(!p(x)){
a = i*(int)Math.pow(-1, i);
i++;
x+=a;
}
System.out.println( (int) Math.abs(x-z));}
this is for n>=2.
In python:
>>> def nearest_prime(n):
incr = -1
multiplier = -1
count = 1
while True:
if prime(n):
return n
else:
n = n + incr
multiplier = multiplier * -1
count = count + 1
incr = multiplier * count
>>> nearest_prime(3)
3
>>> nearest_prime(4)
3
>>> nearest_prime(5)
5
>>> nearest_prime(6)
5
>>> nearest_prime(7)
7
>>> nearest_prime(8)
7
>>> nearest_prime(9)
7
>>> nearest_prime(10)
11
<?php
$N1Diff = null;
$N2Diff = null;
$n1 = null;
$n2 = null;
$number = 16;
function isPrime($x) {
for ($i = 2; $i < $x; $i++) {
if ($x % $i == 0) {
return false;
}
}
return true;
}
for ($j = $number; ; $j--) {
if( isPrime($j) ){
$N1Diff = abs($number - $j);
$n1 = $j;
break;
}
}
for ($j = $number; ; $j++) {
if( isPrime($j) ){
$N2Diff = abs($number - $j);
$n2 = $j;
break;
}
}
if($N1Diff < $N2Diff) {
echo $n1;
} else if ($N1Diff2 < $N1Diff ){
echo $n2;
}
If you want to write an algorithm, A Wikipedia search for prime number led me to another article on the Sieve of Eratosthenes. The algorithm looks a bit simple and I'm thinking a recursive function would suit it well imo. (I could be wrong about that.)
If the array solution isn't a valid solution for you (it is the best one for your scenario), you can try the code below. After the "2 or 3" case, it will check every odd number away from the starting value until it finds a prime.
static int NearestPrime(double original)
{
int above = (int)Math.Ceiling(original);
int below = (int)Math.Floor(original);
if (above <= 2)
{
return 2;
}
if (below == 2)
{
return (original - 2 < 0.5) ? 2 : 3;
}
if (below % 2 == 0) below -= 1;
if (above % 2 == 0) above += 1;
double diffBelow = double.MaxValue, diffAbove = double.MaxValue;
for (; ; above += 2, below -= 2)
{
if (IsPrime(below))
{
diffBelow = original - below;
}
if (IsPrime(above))
{
diffAbove = above - original;
}
if (diffAbove != double.MaxValue || diffBelow != double.MaxValue)
{
break;
}
}
//edit to your liking for midpoint cases (4.0, 6.0, 9.0, etc)
return (int) (diffAbove < diffBelow ? above : below);
}
static bool IsPrime(int p) //intentionally incomplete due to checks in NearestPrime
{
for (int i = 3; i < Math.Sqrt(p); i += 2)
{
if (p % i == 0)
return false;
}
return true;
}
Lookup table whit size of 100 bytes; (unsigned chars)
Round real number and use lookup table.
Maybe we can find the left and right nearest prime numbers, and then compare to get the nearest one. (I've assumed that the next prime number shows up within next 10 occurrences)
def leftnearestprimeno(n):
n1 = n-1
while(n1 >= 0):
if isprime(n1):
return n1
else:
n1 -= 1
return -1
def rightnearestprimeno(n):
n1 = n+1
while(n1 < (n+10)):
if isprime(n1):
return n1
else:
n1 += 1
return -1
n = int(input())
a = leftnearestprimeno(n)
b = rightnearestprimeno(n)
if (n - a) < (b - n):
print("nearest: ", a)
elif (n - a) > (b - n):
print("nearest: ", b)
else:
print("nearest: ", a) #in case the difference is equal, choose min
#value
Simplest answer-
Every prime number can be represented in the form (6*x-1 and 6*X +1) (except 2 and 3).
let number is N.divide it with 6.
t=N/6;
now
a=(t-1)*6
b=(t+1)*6
and check which one is closer to N.

Resources