I have a function that takes in a list of numbers and will return how many even numbers and odd numbers there are in the list. However, I passed in a list of numbers but I'm getting 0 results.
Here is my function -
public static string HowManyEvenAndOdds(List<int> numbers)
{
int numOfOdds = 0;
int numOfEvens = 0;
int numOfBoth = 0;
foreach (int i in numbers) {
bool isEven = i % 2 == 0;
bool isOdd = i % 3 == 0;
numOfBoth = isEven && isOdd ? numOfBoth++ : numOfBoth;
numOfEvens = isEven ? numOfEvens++ : numOfEvens;
numOfOdds = isOdd ? numOfOdds++ : numOfOdds;
}
return string.Format("This list has {0} odd numbers,\n{1} even numbers,\nand {2} numbers that are even and odd.", numOfOdds, numOfEvens, numOfBoth);
}
Any ideas on what I'm doing wrong here? I debugged through it but none of the lists are incrementing.
Thanks
your are not calculating odd in the correct way
i%3 does not catch 5 which is also an odd number, try this instead
bool isEven = i % 2 == 0;
bool isOdd =!isEven;
I agree with Schachaf Gortler's answer as well as p.s.w.g's comment. Just do:
foreach (var number in numbers)
{
// A number is even if, and only if, it's evenly divisible by 2
if (number % 2 == 0)
numEvens++;
// A number is odd if, and only if, it's NOT evenly divisible by 2
// Alternatively, a number is odd if it isn't even and vice versa
else
numOdds++;
}
As p.s.w.g. mentioned, there's no such thing as a number that's both even and odd, so eliminate that completely.
Incidentally, numOfEvens++ retrieves the value and then increments it, which is why your code didn't work.
I think you should have a look at your test for isOdd
Use the Linq Count extension.
int numOfOdds = numbers.Count(x => x % 2 != 0);
int numOfEvens = numbers.Count(x => x % 2 == 0);
Of course you don't need to evaluate both expressions, as per the comment below.
I have been creating a simple chess engine in c# over the last month and made some nice progress on it. It is using a simple Alpha-Beta algorithm.
In order to correct the Horizon-Effect, I tried to implement the Quiescence Search (and failed several times before it worked). The strength of the engine seems to have improved quiet a bit from that, but it is terribly slow!
Before, I could search to a 6 ply depth in about 160 secs (somewhere in a midgame state), with the quiescent search, it takes the computer about 80secs to get a move on search depth 3!
The brute-force node counter is at about 20000 Nodes at depth 3, while the quiescent node counter is up to 20 millions!
Since this is my first chess engine, I don't really know if those numbers are normal or if I might have made a mistake in my Quiescence-Algorithm. I would appreciate if someone more experienced could tell me what the usual ratio of BF Nodes/Quiescent nodes is.
Btw, just to have a look at:
(this Method is called by the BF tree whenever the searchdepth is 0)
public static int QuiescentValue(chessBoard Board, int Alpha, int Beta)
{
QuiescentNodes++;
int MinMax = Board.WhoseMove; // 1 = maximierend, -1 = minimierend
int Counter = 0;
int maxCount;
int tempValue = 0;
int currentAlpha = Alpha;
int currentBeta = Beta;
int QuietWorth = chEvaluation.Evaluate(Board);
if(MinMax == 1) //Max
{
if (QuietWorth >= currentBeta)
return currentBeta;
if (QuietWorth > currentAlpha)
currentAlpha = QuietWorth;
}
else //Min
{
if (QuietWorth <= currentAlpha)
return currentAlpha;
if (QuietWorth < currentBeta)
currentBeta = QuietWorth;
}
List<chMove> HitMoves = GetAllHitMoves(Board);
maxCount = HitMoves.Count;
if(maxCount == 0)
return chEvaluation.Evaluate(Board);
chessBoard tempBoard;
while (Counter < maxCount)
{
tempBoard = new chessBoard(Board);
tempBoard.Move(HitMoves[Counter]);
tempValue = QuiescentValue(tempBoard, currentAlpha, currentBeta);
if (MinMax == 1) //maximierend
{
if (tempValue >= currentBeta)
{
return currentBeta;
}
if (tempValue > currentAlpha)
{
currentAlpha = tempValue;
}
}
else //minimierend
{
if (tempValue <= currentAlpha)
{
return currentAlpha;
}
if (tempValue < currentBeta)
{
currentBeta = tempValue;
}
}
Counter++;
}
if (MinMax == 1)
return currentAlpha;
else
return currentBeta;
}
I am not familliar with the english terminology - is a HitMove a move where you remove a piece from the board?
In that case it seems to me that you use GetAllHitMoves to get a list of the "noisy" moves for the quiescence search which are then evaluated further than the usual 3 or 6 plies. This is called recursively though, so you evaluate this over and over as long as there are possible HitMoves leftover. Giving a limit to your quiescence search should fix your performance issues.
As for choosing the limit for the quiescence search - wiki states:
Modern chess engines may search certain moves up to 2 or 3 times deeper than the minimum.
I'm trying to write a piece of code in C# to find the number digits of a integer number, the code works perfectly for all numbers (negative and positive) but I have problem with 10, 100,1000 and so on, it shows one less digits than the numbers' actual number of digits. like 1 for 10 and 2 for 100..
long i = 0;
double n;
Console.Write("N? ");
n = Convert.ToInt64(Console.ReadLine());
do
{
n = n / 10;
i++;
}
while(Math.Abs(n) > 1);
Console.WriteLine(i);
Your while condition is Math.Abs(n) > 1, but in the case of 10, you are only greater than 1 the first time. You could change this check to be >=1 and that should fix your problem.
do
{
n = n / 10;
i++;
}
while(Math.Abs(n) >= 1);
Use char.IsDigit:
string input = Console.ReadLine();
int numOfDigits = input.Count(char.IsDigit);
What's wrong with:
Math.Abs(n).ToString(NumberFormatInfo.InvariantInfo).Length;
Indeed, converting a number to a string is computationally expensive compared to some arithmetic, but it is hard to deal with negative nubers, overflow,...
You need to use Math.Abs to make sure the sign is not counted, and it is a safe option to use NumberFormatInfo.InvariantInfo so that for instance certain cultures that use spaces and accents, do not alter the behavior.
public static int NumDigits(int value, double #base)
{
if(#base == 1 || #base <= 0 || value == 0)
{
throw new Exception();
}
double rawlog = Math.Log(Math.Abs(value), #base);
return rawlog - (rawlog % 1);
}
This NumDigits function is designed to find the number of digits for a value in any base. It also includes error handling for invalid input. The # with the base variable is to make it a verbatim variable (because base is a keyword).
Console.ReadLine().Replace(",", String.Empty).Length;
this will count all the char in a string
int amount = 0;
string input = Console.ReadLine();
char[] chars = input.ToArray();
foreach (char c in chars)
{
amount++;
}
Console.WriteLine(amount.ToString());
Console.ReadKey();
I have a very specific and long-winded question for you all. This question is both about programming and game-theory. I recently added spawnable ore to my Turn Based Strategy Game: http://imgur.com/gallery/0F5D5Ij (For those of you that look please forgive the development textures).
Now, onto the enigma that I have been contemplating. In my game, ore is generated each time a new map is created. 0-8 ore nodes are generated per level-creation. I already have this working; except it only generates "Emeraldite" at this point, which brings me to my question.
How would I, the programmer, make it so nodes have specific rarity? Consider this short mockup which is not actually game data:
(Pseudo Chances that a node will be one of the following)
Bloodstone 1 in 100
Default(Empty Node) 1 in 10
Copper 1 in 15
Emeraldite 1 in 35
Gold 1 in 50
Heronite 1 in 60
Platinum 1 in 60
Shadownite 1 in 75
Silver 1 in 35
Soranite 1 in 1000
Umbrarite 1 in 1000
Cobalt 1 in 75
Iron 1 in 15
I want to make it so that a generated node could be, theoretically, any of the above, however, with the odds also considered. I hope that question is clear enough. I have been trying to wrap my head around this, and even tried to write out a few if statements with randoms, however, I keep coming up empty handed.
Basically, I just want you guys to see my issue, and hopefully provide me with some insight on how I could approach this in a dynamic kind of way.
If any clarification is needed, please ask; sorry again if this was convoluted.
(I am adding C# as a tag only because that is the language I am using for this project)
I'd first represent the probability of each loot type as a simple number.
A probability in pure mathematics is conventionally expressed as a floating point number in the range 0 to 1, but for efficiency, you can use integers in any (large enough) range (each value is the 0-1 value multiplied by the maximum (which I'm calling MaxProbability here)).
e.g. Bloodstone (1 in 100) is 1/100 = 0.01, or MaxProbability * (1/100).
Copper (1 in 15) is 1/15 = 0.06667, or MaxProbability * (1/15).
I'm assuming that 'Default (Empty Node)' means the probability of none of the others.
In this case, the simplest way is not to define it - you get it if none of the others are chosen.
If 'Default' was included, the sum of all these probabilities would be 1 (i.e. 100%) (or MaxProbability, if using integers).
The 1/10 probability of 'Default' in your example is actually a contradiction because the total of all those probabilities is not 1 (it's 0.38247619 - the sum of the probability as calculated in my examples above).
Then you would choose a random number in the range 0 to 1 (or MaxProbability if using integers), and the chosen loot type is the first one in the list such that the sum of the probabilities of it and all previous ones ("cumulative probability") is greater than the random number.
e.g.
MaxProbability = 1000 (I'm using this to make it easy to read).
(For accurate probabilities, you could use 0x7FFFFFFF).
Type Probability Cumulative
---- ----------- ----------
Bloodstone 10 10 (0..9 yield Bloodstone)
Copper 67 77 (10+67) (10..76 yield Copper)
Emeraldite 29 105 (77+29)
Gold 20 125 etc.
Heronite 17 142
Platinum 17 159
Shadownite 13 172
Silver 29 200
Soranite 1 201
Umbrarite 1 202
Cobalt 13 216
Iron 67 282
Default (Empty Node) 7175 1000 (anything else)
e.g. If your random number in the range 0 to 999 (inclusive) was 184 (or anything in the range 172 to 199), you would choose "Silver" (the first one with cumulative probability greater than this).
You could hold the cumulative probabilities in an array and loop through it until you find one higher than the random number, or reach the end.
The order of the list does not matter.
You chose a random number only once per instance.
Including 'Default (Empty Node)' in the list means that the last cumulative probability will always be MaxProbability and the loop that searches it would never go past the end. (Alternatively, 'Default' can be omitted, and you choose it if the loop reaches the end of the list.)
Note that choosing a random number for each one in turn, e.g. a 1/10 chance of 'Bloodstone', then a 1/15 chance of Copper if not Bloodstone, skews the probabilities towards the earlier items:
The actual probability of Copper would be (1/15) * (1 - (1/10)) - 10% less than 1/15.
Here's code to do it (the actual choosing is 5 statements - in the method Choose ).
using System;
namespace ConsoleApplication1
{
class LootChooser
{
/// <summary>
/// Choose a random loot type.
/// </summary>
public LootType Choose()
{
LootType lootType = 0; // start at first one
int randomValue = _rnd.Next(MaxProbability);
while (_lootProbabilites[(int)lootType] <= randomValue)
{
lootType++; // next loot type
}
return lootType;
}
/// <summary>
/// The loot types.
/// </summary>
public enum LootType
{
Bloodstone, Copper, Emeraldite, Gold, Heronite, Platinum,
Shadownite, Silver, Soranite, Umbrarite, Cobalt, Iron, Default
};
/// <summary>
/// Cumulative probabilities - each entry corresponds to the member of LootType in the corresponding position.
/// </summary>
protected int[] _lootProbabilites = new int[]
{
10, 77, 105, 125, 142, 159, 172, 200, 201, 202, 216, 282, // (from the table in the answer - I used a spreadsheet to generate these)
MaxProbability
};
/// <summary>
/// The range of the probability values (dividing a value in _lootProbabilites by this would give a probability in the range 0..1).
/// </summary>
protected const int MaxProbability = 1000;
protected Random _rnd = new Random((int)(DateTime.Now.Ticks & 0x7FFFFFFF));
/// <summary>
/// Simple 'main' to demonstrate.
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
var chooser = new LootChooser();
for(int n=0; n < 100; n++)
Console.Out.WriteLine(chooser.Choose());
}
}
}
You could rewrite all chances so that they use the same divisor (e.g. 1000), your chances then become
Bloodstone 10 in 1000
Default(Empty Node) 100 in 1000
Gold 20 in 1000
Next, create an array of a 1000 elements, and fill it with
10 Bloodstone elements,
100 Empty elements,
20 Gold elements,
etc.
Finally, generate a random number between 0 and 1000, and use that as the index into the element array, this will give
you your random element.
You might have to play with the chances a bit, since you'll probably want all 1000 array elements to be filled, but this is the general idea.
edit its not the most efficient implementation (at least in terms of memory usage, its running time should be good), but I chose this since it allows for a concise explanation that doesn't require a whole lot of math.
First of all, specifying the the default-empty node's probability is unnecessary. The other probabilities should be defined in such a way, that the empty node is created if no other type is created.
How to do this and ensure the generation probabiltiies are equal to those you specified? In short:
convert the probabilities to a floating point (it's a value with a common divisor of 1)
sum all probabilities and check if they are < 1
write a class which will store the all the probabilities
write a function which will get a random node based on those probabilities
For your example:
Bloodstone 1 in 100 = 0.01
Copper 1 in 15 ~= 0.07
Emeraldite 1 in 35 ~= 0.03
Gold 1 in 50 = 0.02
Default = 0.87
Now the class can be implemented in at least two ways. My option consumes much memory, does the computations once, but it also rounds the probability values which may introduce some error. Note, that the error depends on the arrSize variable - the larger it is, the smaller the error.
The other option is as in Bogusz's answer. It is more precise, but required more operations per each generated element.
Option suggested by Thomas requires a lot of repeatable code for each option hence is not versatile. Shellshock's answer will have invalid effective probabilities.
Astrotrain's idea to force yourself to use the same divisor is virtually the same as my own, though the implementation would be slightly different.
Here's a sample implementation of my idea (in java, but should be ported very easily):
public class NodeEntry {
String name;
double probability;
public NodeEntry(String name, double probability) {
super();
this.name = name;
this.probability = probability;
}
public NodeEntry(String name, int howMany, int inHowMany) {
this.name = name;
this.probability = 1.0 * howMany / inHowMany;
}
public final String getName() {
return name;
}
public final void setName(String name) {
this.name = name;
}
public final double getProbability() {
return probability;
}
public final void setProbability(double probability) {
this.probability = probability;
}
#Override
public String toString() {
return name+"("+probability+")";
}
static final NodeEntry defaultNode = new NodeEntry("default", 0);
public static final NodeEntry getDefaultNode() {
return defaultNode;
}
}
public class NodeGen {
List<NodeEntry> nodeDefinitions = new LinkedList<NodeEntry>();
public NodeGen() {
}
public boolean addNode(NodeEntry e) {
return nodeDefinitions.add(e);
}
public boolean addAllNodes(Collection<? extends NodeEntry> c) {
return nodeDefinitions.addAll(c);
}
static final int arrSize = 10000;
NodeEntry randSource[] = new NodeEntry[arrSize];
public void compile() {
checkProbSum();
int offset = 0;
for (NodeEntry ne: nodeDefinitions) {
int amount = (int) (ne.getProbability() * arrSize);
for (int a=0; a<amount;a++) {
randSource[a+offset] = ne;
}
offset+=amount;
}
while (offset<arrSize) {
randSource[offset] = NodeEntry.getDefaultNode();
offset++;
}
}
Random gen = new Random();
public NodeEntry getRandomNode() {
return randSource[gen.nextInt(arrSize)];
}
private void checkProbSum() {
double sum = 0;
for (NodeEntry ne: nodeDefinitions) {
sum+=ne.getProbability();
}
if (sum >1) {
throw new RuntimeException("nodes probability > 1");
}
}
public static void main(String[] args) {
NodeGen ng = new NodeGen();
ng.addNode(new NodeEntry("Test 1", 0.1));
ng.addNode(new NodeEntry("Test 2", 0.2));
ng.addNode(new NodeEntry("Test 3", 0.2));
ng.compile();
Map<NodeEntry, Integer> resCount = new HashMap<NodeEntry, Integer>();
int generations = 10000;
for (int a=0; a<generations; a++) {
NodeEntry node = ng.getRandomNode();
Integer val = resCount.get(node);
if (val == null) {
resCount.put(node, new Integer(1));
} else {
resCount.put(node, new Integer(val+1));
}
}
for (Map.Entry<NodeEntry, Integer> entry: resCount.entrySet()) {
System.out.println(entry.getKey()+": "+entry.getValue()+" ("+(100.0*entry.getValue()/generations)+"%)");
}
}
}
This makes sure the probabilities are actually uniform. If you checked for the first node spawn, then the other, then the other - you would get wrong results: nodes checked first would have increased probability.
Sample run:
Test 2(0.2): 1975 (19.75%)
Test 1(0.1): 1042 (10.42%)
Test 3(0.2): 1981 (19.81%)
default(0.0): 5002 (50.02%)
I think that it is easy to understand how it works.
(Cobalt, 20: means 1 of 20 -> 5%)
Dictionary<string, double> ore = new Dictionary<string, double>();
Random random = new Random();
private void AddOre(string Name, double Value)
{
ore.Add(Name, 1.0 / Value);
}
private string GetOreType()
{
double probSum = 0;
double rand = random.NextDouble();
foreach (var pair in ore)
{
probSum += pair.Value;
if (probSum >= rand)
return pair.Key;
}
return "Normal Ore"; //Reaches this point only if an error occurs.
}
private void Action()
{
AddOre("Cobalt", 20);
AddOre("Stone", 10);
AddOre("Iron", 100);
AddOre("GreenOre", 300);
//Add Common ore and sort Dictionary
AddOre("Common ore", 1 / (1 - ore.Values.Sum()));
ore = ore.OrderByDescending(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
Console.WriteLine(GetOreType());
}
Edit:
I add section "Add Common ore and sort Dictionary".
I recently had to do something similar, and I ended up with this generic "spawn generator".
public interface ISpawnable : ICloneable
{
int OneInThousandProbability { get; }
}
public class SpawnGenerator<T> where T : ISpawnable
{
private class SpawnableWrapper
{
readonly T spawnable;
readonly int minThreshold;
readonly int maxThreshold;
public SpawnableWrapper(T spawnable, int minThreshold)
{
this.spawnable = spawnable;
this.minThreshold = minThreshold;
this.maxThreshold = this.minThreshold + spawnable.OneInThousandProbability;
}
public T Spawnable { get { return this.spawnable; } }
public int MinThreshold { get { return this.minThreshold; } }
public int MaxThreshold { get { return this.maxThreshold; } }
}
private ICollection<SpawnableWrapper> spawnableEntities;
private Random r;
public SpawnGenerator(IEnumerable<T> objects, int seed)
{
Debug.Assert(objects != null);
r = new Random(seed);
var cumulativeProbability = 0;
spawnableEntities = new List<SpawnableWrapper>();
foreach (var o in objects)
{
var spawnable = new SpawnableWrapper(o, cumulativeProbability);
cumulativeProbability = spawnable.MaxThreshold;
spawnableEntities.Add(spawnable);
}
Debug.Assert(cumulativeProbability <= 1000);
}
//Note that it can spawn null (no spawn) if probabilities dont add up to 1000
public T Spawn()
{
var i = r.Next(0, 1000);
var retVal = (from s in this.spawnableEntities
where (s.MaxThreshold > i && s.MinThreshold <= i)
select s.Spawnable).FirstOrDefault();
return retVal != null ? (T)retVal.Clone() : retVal;
}
}
And you'd use it like:
public class Gem : ISpawnable
{
readonly string color;
readonly int oneInThousandProbability;
public Gem(string color, int oneInThousandProbability)
{
this.color = color;
this.oneInThousandProbability = oneInThousandProbability;
}
public string Color { get { return this.color; } }
public int OneInThousandProbability
{
get
{
return this.oneInThousandProbability;
}
}
public object Clone()
{
return new Gem(this.color, this.oneInThousandProbability);
}
}
var RedGem = new Gem("Red", 250);
var GreenGem = new Gem("Green", 400);
var BlueGem = new Gem("Blue", 100);
var PurpleGem = new Gem("Purple", 190);
var OrangeGem = new Gem("Orange", 50);
var YellowGem = new Gem("Yellow", 10);
var spawnGenerator = new SpawnGenerator<Gem>(new[] { RedGem, GreenGem, BlueGem, PurpleGem, OrangeGem, YellowGem }, DateTime.Now.Millisecond);
var randomGem = spawnGenerator.Spawn();
Evidently the spawn algorithm was not considered critical code so the overhead of this implementation was of no concern when compared to the ease of use. Spawns were run on world creation and it was easily more than fast enough.
Astrotrain already gave my answer but since I coded it up already I'll post it. Sorry for the syntax, I work mostly in Powershell and that is the context currently in my mind. Consider this psuedo code:
// Define the odds for each loot type
// Description,Freq,Range
LootOddsArray = "Bloodstone",1,100,
"Copper",1,15,
"Emeraldite,"1,35,
"Gold",1,50,
"Heronite",1,60,
"Platinum",1,60,
"Shadownite",1,75,
"Silver",1,35,
"Soranite",1,1000,
"Umbrarite",1,1000,
"Cobalt",1,75,
"Iron",1,15
// Define your lookup table. It should be as big as your largest odds range.
LootLookupArray(1000)
// Fill all the 'default' values with "Nothing"
for (i=0;i<LootLookupArray.length;i++) {
LootOddsArray(i) = "Nothing"
}
// Walk through your various treasures
for (i=0;i<LootOddsArray.length;i++)
// Calculate how often the item will appear in the table based on the odds
// and place that many of the item in random places in the table, not overwriting
// any other loot already in the table
NumOccsPer1000 = Round(LootOddsArray(i).Freq * 1000/LootOddsArray(i).Range)
for (l=0;l<NumOccsPer1000;l++) {
// Find an empty slot for the loot
do
LootIndex = Random(1000)
while (LootLookupArray(LootIndex) != "Nothing")
// Array(Index) is empty, put loot there
LootLookupArray(LootIndex) = LootOddsArray(i).Description
}
}
// Roll for Loot
Loot = LootLookupArray(Random(1000))
Use Random.Next http://msdn.microsoft.com/en-us/library/2dx6wyd4(v=vs.110).aspx:
Random rnd = new Random();
if (rnd.Next(1, 101) == 1)
// spawn Bloodstone
if (rnd.Next(1, 16) == 1)
// spawn Copper
if (rnd.Next(1, 36) == 1)
// spawn Emeraldite
The minimum value should always be 1, the maximum value is the odds of spawning the item + 1 (minValue is inclusive, maxValue is exclusive). Always test the return value for 1, e.g., for Bloodstone there is a 1 in 100 chance that the randomly generated number is 1. Of course, this uses a pseudo random number generator, which should be good enough for a game.
A slightly different approach to Astrotrains idea would be that instead of an array to use if statements . The upside is then that you need less memory, the downside that it will need more cpu time to calc the value of the node.
Thus:
Random rnd = new Random();
var number = rnd.next(1,1000);
if (number >= 1 && number <10)
{
// empty
}
else
{
if (number >= 10 && number <100)
{
// bloodstone
}
else
{
//......
}
}
Also a downside to this variant comapred to the array variant is that this one takes more place codewise at the location where you use it and is more prone to errors / corrections (try to add something inside it you need to update all variants).
Thus this here is metnioned for completeness sake but the array vairant (memory usage aside) is less prone to the problems that the if variant has.
I coded up a program in C# to find perfect numbers within a certain range as part of a programming challenge . However, I realized it is very slow when calculating perfect numbers upwards of 10000. Are there any methods of optimization that exist for finding perfect numbers? My code is as follows:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleTest
{
class Program
{
public static List<int> FindDivisors(int inputNo)
{
List<int> Divisors = new List<int>();
for (int i = 1; i<inputNo; i++)
{
if (inputNo%i==0)
Divisors.Add(i);
}
return Divisors;
}
public static void Main(string[] args)
{
const int limit = 100000;
List<int> PerfectNumbers = new List<int>();
List<int> Divisors=new List<int>();
for (int i=1; i<limit; i++)
{
Divisors = FindDivisors(i);
if (i==Divisors.Sum())
PerfectNumbers.Add(i);
}
Console.Write("Output =");
for (int i=0; i<PerfectNumbers.Count; i++)
{
Console.Write(" {0} ",PerfectNumbers[i]);
}
Console.Write("\n\n\nPress any key to continue . . . ");
Console.ReadKey(true);
}
}
}
Use the formula
testPerfect = 2n-1(2n - 1)
to generate possiblities then check wether the number is in fact perfect.
try this for some bedtime reading
Do perfect numbers change? No. Look here. Surely, they should be calculated once and then stored.
In your case, the only results will be
6
28
496
8128
The next one is 33550336. Outside your range.
Just the obvious one from me: you don't need to check every divisor. No point looking for divisors past inputNo/2. That cuts down half of the calculations, but this is not an order of magnitude faster.
One way to solve things like this involves building a huge array in memory of every number, and then crossing numbers out.
if your still looking for something to calculate perfect numbers.
this goes through the first ten thousand pretty quick, but the 33 million number is a little slower.
public class Perfect {
private static Perfect INSTANCE = new Perfect();
public static Perfect getInstance() {
return INSTANCE;
}
/**
* the method that determines if a number is perfect;
*
* #param n
* #return
*/
public boolean isPerfect(long n) {
long i = 0;
long value = 0;
while(++i<n){
value = (0 == n%i?value+i:value);
}
return n==value;
}
}
For anyone interested in a LINQ based approach, the following method worked quite well and efficiently for me in determining whether or not a caller supplied integer value is a perfect number.
bool IsPerfectNumber(int value)
{
var isPerfect = false;
int maxCheck = Convert.ToInt32(Math.Sqrt(value));
int[] possibleDivisors = Enumerable.Range(1, maxCheck).ToArray();
int[] properDivisors = possibleDivisors.Where(d => (value % d == 0)).Select(d => d).ToArray();
int divisorsSum = properDivisors.Sum();
if (IsPrime(divisorsSum))
{
int lastDivisor = properDivisors.Last();
isPerfect = (value == (lastDivisor * divisorsSum));
}
return isPerfect;
}
For simplicity and clarity, my implementation for IsPrime(), which is used within IsPerfectNumber(), is omitted.
To continue from Charles Gargent's answer there is a very quick way to check if a Mersenne Number a.k.a. 2^n - 1 is prime. It is called the Lucas-Lehmer test
The basic pseudocode though (taken from the Wikipedia page) is:
// Determine if Mp = 2p − 1 is prime for p > 2
Lucas–Lehmer(p)
var s = 4
var M = 2p − 1
repeat p − 2 times:
s = ((s × s) − 2) mod M
if s == 0 return PRIME else return COMPOSITE