C #, pas de boucles
OK, j'ai survolé quelques-uns de ces liens, mais pour être honnête, ils étaient un peu ennuyeux. Je ne suis pas intéressé à optimiser l'enfer avec des tables de hachage et ainsi de suite. Pourquoi devrais-je en avoir besoin? Vous avez un putain de supercalculateur!
Enfer, je ne veux même pas m'embêter avec des boucles! Cette solution suivra la règle no-loops .
Veuillez noter que le code que je suis sur le point d'écrire n'est pas un bon code, ou le type de code que j'écrirais dans la vraie vie (au cas où des employeurs potentiels liraient cela). Ce code met l'accent sur la brièveté et la capacité de travailler dans un récit, et met l'accent sur les conventions et les rituels et boucles appropriés, etc.
Pour démontrer de quoi je parle, nous allons commencer par une classe choquante avec des champs publics pour stocker les opérandes de l'équation:
class BealOperands
{
public BigInteger A, B, C, x, y, z;
}
OK, nous allons commencer par ce qui est probablement le défi le plus difficile. Nous devons trouver un moyen de permuter à travers chaque combinaison de ces opérandes. Il existe sans aucun doute des moyens de le faire plus efficacement que de vérifier chaque permutation, mais je ne peux pas être dérangé de les découvrir. Et pourquoi devrais-je? Nous avons un putain de supercalculateur!
Voici l'algorithme que j'ai trouvé. C'est incroyablement inefficace et répète encore et encore les mêmes opérandes, mais qui s'en soucie? Supercalculateur!
- Traitez les six opérandes comme un nombre en base 2 et permutez à travers chaque combinaison.
- Traitez les six opérandes comme un nombre en base 3 et permutez à travers chaque combinaison.
- Traitez les six opérandes comme un nombre en base 4 et permutez à travers chaque combinaison.
- (...)
Comment faire tout cela sans boucles? Facile! Il suffit de mettre en œuvre un IEnumerable
et associé IEnumerator
pour pomper les permutations. Plus tard, nous utiliserons LINQ pour l'interroger.
class BealOperandGenerator : IEnumerable<BealOperands>
{
// Implementation of IEnumerable<> and IEnumerable -- basically boilerplate to get to BealOperandGeneratorEnumerator.
public IEnumerator<BealOperands> GetEnumerator() { return new BealOperandGeneratorEnumerator(); }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
class BealOperandGeneratorEnumerator : IEnumerator<BealOperands>
{
public BealOperandGeneratorEnumerator() { Reset(); }
private BealOperands operands;
private BigInteger @base;
public void Reset()
{
// A is set to 0, which is "before" its minimum value, because IEnumerators are supposed to
// point to their first element *after* the first call to MoveNext().
// All other operands are set to their minimum values.
operands = new BealOperands { A = 0, B = 1, C = 1, x = 3, y = 3, z = 3 };
@base = 2;
}
public BealOperands Current
{
get
{
// We need to return a copy, since we'll be manipulating our internal one.
return new BealOperands {
A = operands.A, B = operands.B, C = operands.C,
x = operands.x, y = operands.y, z = operands.z };
}
}
public bool MoveNext()
{
// Increment the lowest "digit" and "carry" as necessary.
operands.A++;
if (operands.A - 1 >= @base)
{
operands.A = 1; operands.B++;
if (operands.B - 1 >= @base)
{
operands.B = 1; operands.C++;
if (operands.C - 1 >= @base)
{
operands.C = 1; operands.x++;
if (operands.x - 3 >= @base)
{
operands.x = 3; operands.y++;
if (operands.y - 3 >= @base)
{
operands.y = 3; operands.z++;
if (operands.z - 3 >= @base)
{
operands.z = 3; @base++;
}
}
}
}
}
}
// There will always be more elements in this sequence.
return true;
}
// More boilerplate
object System.Collections.IEnumerator.Current { get { return Current; } }
public void Dispose() { }
}
Maintenant, nous sommes en affaires! Tout ce que nous devons faire est d'énumérer une instance de BealOperandGenerator
et de trouver un contre-exemple de la conjecture de Beal.
Notre prochain gros problème est qu'il ne semble pas y avoir de moyen intégré d'élever a BigInteger
au pouvoir de a BigInteger
. Il y a BigInteger.Pow(BigInteger value, int exponent)
et BigInteger.ModPow(BigInteger value, BigInteger exponent, BigInteger modulus)
, mais pas de méthode pour élever un BigInteger
, à la puissance d'un autre BigInteger
, l'infini modulo.
Quel clou brillant d'un problème! On dirait qu'il a été fait pour être résolu avec notre IEnumerable
/ IEnumerator
hammer!
class BigIntegerPowerEnumerable : IEnumerable<Tuple<BigInteger, BigInteger>>
{
public BigIntegerPowerEnumerable(BigInteger @base, BigInteger exponent) { this.@base = @base; this.exponent = exponent; }
BigInteger @base, exponent;
public IEnumerator<Tuple<BigInteger, BigInteger>> GetEnumerator() { return new BigIntegerPowerEnumerator(@base, exponent); }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
class BigIntegerPowerEnumerator : IEnumerator<Tuple<BigInteger, BigInteger>>
{
public BigIntegerPowerEnumerator(BigInteger @base, BigInteger exponent)
{
originalBase = @base;
originalExponent = exponent;
Reset();
}
BigInteger originalBase, currentBase, originalExponent, currentExponent;
bool finished;
public void Reset()
{
// IEnumerable.Reset() is a silly method. You're required to implement it when you implement IEnumerable,
// but it isn't used by foreach or LINQ or anything. If you want to re-enumerate the enumerable, just get
// a brand new enumerator.
// In this case it gets in the way. The only reason I'm storing the original values is so I can implement
// this useless method properly. I supposed I could just throw a NotImplementedException or something,
// but it's done now.
currentBase = originalBase;
currentExponent = originalExponent;
finished = false;
}
public bool MoveNext()
{
if (finished) return false;
if (currentExponent <= Int32.MaxValue)
{
currentBase = BigInteger.Pow(currentBase, (Int32)currentExponent);
currentExponent = 1;
finished = true;
}
else
{
currentBase = BigInteger.Pow(currentBase, Int32.MaxValue);
currentExponent -= Int32.MaxValue;
}
return true;
}
public Tuple<BigInteger, BigInteger> Current
{
get { return new Tuple<BigInteger, BigInteger>(currentBase, currentExponent); }
}
object System.Collections.IEnumerator.Current { get { return Current; } }
public void Dispose() { }
}
static class BigIntegerPowExtension
{
public static BigInteger Pow(this BigInteger @base, BigInteger exponent)
{
return new BigIntegerPowerEnumerable(@base, exponent).Last().Item1;
}
}
Nous avons maintenant une méthode d'extension Pow
, qui peut être appelée sur un BigInteger
, et prend un BigInteger
exposant et aucun module.
OK, reculons. Comment savoir si un particulier BealOperands
est un contre-exemple de la conjecture de Beal? Eh bien, deux choses doivent être vraies:
- Les opérandes, lorsqu'ils sont connectés à cette formule en haut de la page, doivent former une véritable équation.
- A, B et C ne doivent PAS avoir un facteur premier commun (c'est-à-dire que leur GCD est 1).
Nous avons ce dont nous avons besoin pour vérifier la première condition. Et il s'avère que la deuxième condition est beaucoup plus facile à vérifier qu'il n'y paraît. BigInteger
fournit une belle GreatestCommonDivisor
méthode, qui nous permet de contourner commodément tout le cauchemar d'essayer de l'implémenter sans boucles.
Nous sommes donc prêts à écrire une méthode pour vérifier si a BealOperands
est un contre-exemple. Voici...
static class BealOperandsExtensions
{
public static bool IsBealsConjectureCounterExample(this BealOperands o)
{
// If the equation isn't even true, we don't have a counter example unfortunately
if (o.A.Pow(o.x) + o.B.Pow(o.y) != o.C.Pow(o.z))
{
return false;
}
// We have a counterexample if A, B and C are coprime
return BigInteger.GreatestCommonDivisor(o.A, o.B) == 1 &&
BigInteger.GreatestCommonDivisor(o.A, o.C) == 1 &&
BigInteger.GreatestCommonDivisor(o.B, o.C) == 1;
}
}
Et enfin, nous pouvons tout rassembler avec cette Main
méthode plutôt simple:
static class Program
{
static void Main()
{
var bealOperandGenerator = new BealOperandGenerator();
if (bealOperandGenerator.Any(o => o.IsBealsConjectureCounterExample()))
{
Console.WriteLine("IN YOUR FACE, BEAL!");
}
}
}