C #, keine Schleifen
OK, ich habe ein paar dieser Links überflogen, aber um ehrlich zu sein, sie waren ein bisschen langweilig. Ich bin nicht daran interessiert, das Ganze mit Hash-Tabellen und so weiter zu optimieren. Warum sollte ich brauchen? Du hast einen verdammten Supercomputer!
Verdammt, ich möchte mich nicht einmal mit Schleifen beschäftigen! Diese Lösung folgt der No-Loops-Regel .
Bitte beachten Sie, dass der Code, den ich gerade schreibe, kein guter Code ist oder die Art von Code, die ich im wirklichen Leben schreibe (falls potenzielle Arbeitgeber dies zufällig lesen). Dieser Code betont die Kürze und die Fähigkeit, in einer Erzählung zu arbeiten, und betont die richtigen Konventionen und Rituale und Schleifen und so weiter.
Um zu demonstrieren, wovon ich spreche, beginnen wir mit einer schockierenden Klasse mit öffentlichen Feldern, um die Operanden der Gleichung zu speichern:
class BealOperands
{
public BigInteger A, B, C, x, y, z;
}
OK, wir beginnen mit der wahrscheinlich schwierigsten Herausforderung. Wir müssen einen Weg finden, durch jede Kombination dieser Operanden zu permutieren. Es gibt zweifellos Möglichkeiten, dies effizienter zu tun, als jede Permutation zu überprüfen, aber ich kann mich nicht darum kümmern, sie herauszufinden. Und warum sollte ich Wir haben einen verdammten Supercomputer!
Hier ist der Algorithmus, den ich mir ausgedacht habe. Es ist unglaublich ineffizient und geht immer wieder dieselben Operanden durch, aber wen interessiert das? Supercomputer!
- Behandle die sechs Operanden als Zahl zur Basis 2 und permutiere durch jede Kombination.
- Behandle die sechs Operanden als Zahl zur Basis 3 und permutiere durch jede Kombination.
- Behandle die sechs Operanden als eine Zahl zur Basis 4 und permutiere durch jede Kombination.
- (...)
Wie geht das alles ohne Schleifen? Einfach! Implementieren Sie einfach ein IEnumerable
und das zugehörige IEnumerator
, um die Permutationen abzupumpen. Später werden wir LINQ verwenden, um es abzufragen.
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() { }
}
Jetzt sind wir im Geschäft! Alles, was wir tun müssen, ist eine Instanz von aufzählen BealOperandGenerator
und ein Gegenbeispiel von Beals Vermutung zu finden.
Unser nächstes großes Problem ist, dass es keinen eingebauten Weg zu geben scheint, um a BigInteger
zur Macht von a zu erheben BigInteger
. Es gibt BigInteger.Pow(BigInteger value, int exponent)
, BigInteger.ModPow(BigInteger value, BigInteger exponent, BigInteger modulus)
aber keine Methode, um eine Modulo-Unendlichkeit BigInteger
zur Macht einer anderen zu erheben BigInteger
.
Was für ein glänzender Nagel für ein Problem! Es sieht aus wie es gemacht wurde mit unserem zu lösenden 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;
}
}
Jetzt haben wir eine Erweiterungsmethode Pow
, die für a aufgerufen werden BigInteger
kann und einen BigInteger
Exponenten und keinen Modul annimmt .
OK, lass uns zurücktreten. Wie können wir feststellen, ob ein bestimmtes BealOperands
Objekt ein Gegenbeispiel für Beals Vermutung ist? Nun, zwei Dinge müssen stimmen:
- Wenn die Operanden oben auf der Seite in diese Formel eingefügt werden, müssen sie eine wahre Gleichung bilden.
- A, B und C dürfen KEINEN gemeinsamen Primfaktor haben (dh ihr GCD ist 1).
Wir haben das, was wir brauchen, um die erste Bedingung zu überprüfen. Und es stellt sich heraus, dass die zweite Bedingung viel einfacher zu überprüfen ist als es sich anhört. BigInteger
bietet eine schöne GreatestCommonDivisor
Methode, mit der wir den ganzen Albtraum, dies ohne Schleifen umzusetzen, bequem umgehen können.
Wir sind also bereit, eine Methode zu schreiben, um zu überprüfen, ob a BealOperands
ein Gegenbeispiel ist. Hier geht...
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;
}
}
Und schließlich können wir alles mit dieser ziemlich raffinierten Main
Methode zusammenbringen:
static class Program
{
static void Main()
{
var bealOperandGenerator = new BealOperandGenerator();
if (bealOperandGenerator.Any(o => o.IsBealsConjectureCounterExample()))
{
Console.WriteLine("IN YOUR FACE, BEAL!");
}
}
}