C #, tidak ada loop
OK, saya membaca sekilas beberapa tautan itu, tetapi jujur saja itu agak membosankan. Saya tidak tertarik mengoptimalkannya dengan tabel hash dan yang lainnya. Mengapa saya harus melakukannya? Anda punya superkomputer!
Sial, aku bahkan tidak mau repot dengan loop! Solusi ini akan mengikuti aturan no-loop .
Harap perhatikan bahwa kode yang akan saya tulis bukan kode yang baik, atau jenis kode yang akan saya tulis dalam kehidupan nyata (jika calon majikan kebetulan membaca ini). Kode ini menekankan keringkasan dan kemampuan untuk bekerja dalam narasi, dan menekankan konvensi dan ritual yang tepat dan loop dan sebagainya.
Untuk menunjukkan apa yang saya bicarakan, kita akan mulai dengan kelas yang mengejutkan dengan bidang publik untuk menyimpan operan dari persamaan:
class BealOperands
{
public BigInteger A, B, C, x, y, z;
}
Oke, kita akan mulai dengan apa yang mungkin merupakan tantangan terberat. Kita perlu mencari cara untuk mengubah urutan melalui setiap kombinasi operan tersebut. Tidak diragukan lagi ada cara untuk melakukannya dengan lebih efisien daripada memeriksa setiap permutasi, tetapi saya tidak dapat diganggu untuk mencari tahu mereka. Dan mengapa saya harus? Kita punya superkomputer!
Inilah algoritma yang saya buat. Ini sangat tidak efisien, dan mengulangi operan yang sama berulang-ulang, tetapi siapa yang peduli? Komputer Super!
- Perlakukan keenam operan sebagai angka dasar-2, dan permutasi melalui setiap kombinasi.
- Perlakukan keenam operan sebagai angka dasar-3, dan permutasi melalui setiap kombinasi.
- Perlakukan keenam operan sebagai angka dasar-4, dan permutasi melalui setiap kombinasi.
- (...)
Bagaimana melakukan semua ini tanpa loop? Mudah! Hanya menerapkan IEnumerable
dan terkait IEnumerator
untuk memompa permutasi. Nantinya, kami akan menggunakan LINQ untuk menanyakannya.
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() { }
}
Sekarang kita dalam bisnis! Yang perlu kita lakukan hanyalah menyebutkan contoh BealOperandGenerator
dan menemukan contoh tandingan Beal's Conjecture.
Masalah besar kita berikutnya adalah bahwa tampaknya tidak ada cara bawaan untuk meningkatkan BigInteger
kekuatan a BigInteger
. Ada BigInteger.Pow(BigInteger value, int exponent)
, dan BigInteger.ModPow(BigInteger value, BigInteger exponent, BigInteger modulus)
, tetapi tidak ada metode untuk meningkatkan BigInteger
, ke kekuatan yang lain BigInteger
, modulo infinity.
Sungguh kuku yang mengkilap dari suatu masalah! Sepertinya itu dibuat untuk dipecahkan dengan kami IEnumerable
/ IEnumerator
palu!
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;
}
}
Sekarang kita punya metode ekstensi Pow
, yang dapat dipanggil pada BigInteger
, dan membutuhkan BigInteger
eksponen dan tanpa modulus.
Oke, mari kita mundur. Bagaimana kita bisa tahu jika orang tertentu BealOperands
adalah contoh tandingan Beal's Conjecture? Nah, dua hal harus benar:
- Operan, ketika dicolokkan ke rumus itu di bagian atas halaman, harus membentuk persamaan yang benar.
- A, B, dan C TIDAK boleh memiliki faktor prima yang sama (yaitu GCD-nya adalah 1).
Kami memiliki apa yang kami butuhkan untuk memeriksa kondisi pertama. Dan ternyata kondisi kedua jauh lebih mudah untuk diperiksa daripada kedengarannya. BigInteger
menyediakan GreatestCommonDivisor
metode yang bagus , yang memungkinkan kita untuk dengan mudah menghindari seluruh mimpi buruk untuk mencoba mengimplementasikannya tanpa loop.
Jadi kami siap menulis metode untuk memeriksa apakah a BealOperands
adalah contoh tandingan. Ini dia ...
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;
}
}
Dan akhirnya kita bisa menggabungkan semuanya dengan Main
metode yang cukup apik ini:
static class Program
{
static void Main()
{
var bealOperandGenerator = new BealOperandGenerator();
if (bealOperandGenerator.Any(o => o.IsBealsConjectureCounterExample()))
{
Console.WriteLine("IN YOUR FACE, BEAL!");
}
}
}