C # ไม่มีลูป
ตกลงฉันอ่านลิงก์เหล่านี้สองสามอัน แต่จริงๆแล้วพวกเขาน่าเบื่อนิดหน่อย ฉันไม่สนใจที่จะปรับนรกให้เหมาะสมด้วยตารางแฮชและอะไรก็ตาม ทำไมฉันต้อง คุณมีซูเปอร์คอมพิวเตอร์คนหนึ่ง!
นรกฉันไม่ต้องการที่จะห่วงกับลูป! การแก้ปัญหานี้จะเป็นไปตามกฎไม่มีลูป
โปรดทราบว่ารหัสที่ฉันจะเขียนนั้นไม่ได้เป็นรหัสที่ดีหรือรหัสที่ฉันเขียนในชีวิตจริง (ในกรณีที่มีผู้ว่าจ้างที่คาดหวังที่จะอ่านข้อความนี้) รหัสนี้เน้นความกะทัดรัดและความสามารถในการทำงานในการบรรยายและ deemphasises การประชุมและพิธีกรรมที่เหมาะสมและลูปและอื่น ๆ
เพื่อแสดงให้เห็นถึงสิ่งที่ฉันกำลังพูดถึงเราจะเริ่มด้วยคลาสที่น่าตกใจด้วยฟิลด์สาธารณะเพื่อจัดเก็บตัวถูกดำเนินการของสมการ:
class BealOperands
{
public BigInteger A, B, C, x, y, z;
}
ตกลงเราจะเริ่มด้วยสิ่งที่อาจเป็นความท้าทายที่ยากที่สุด เราจำเป็นต้องหาวิธีในการเปลี่ยนรูปจากการรวมกันของตัวถูกดำเนินการเหล่านั้น มีวิธีการอย่างไม่ต้องสงสัยในการทำอย่างมีประสิทธิภาพมากกว่าการตรวจสอบการเปลี่ยนแปลงทุกครั้ง แต่ฉันไม่สามารถคิดออกได้ แล้วทำไมฉันต้อง เรามีซูเปอร์คอมพิวเตอร์ที่น่ากลัว!
นี่คืออัลกอริทึมที่ฉันคิดขึ้นมา มันไม่มีประสิทธิภาพอย่างไม่น่าเชื่อและไปยังตัวถูกดำเนินการเดียวกันซ้ำแล้วซ้ำอีก แต่ใครจะสนใจ? ซูเปอร์คอมพิวเตอร์!
- ให้ถือว่าตัวถูกดำเนินการทั้งหกเป็นหมายเลขฐาน 2 และเปลี่ยนผ่านทุกชุดค่าผสม
- ถือว่าตัวถูกดำเนินการทั้งหกเป็นหมายเลขฐาน 3 และเปลี่ยนรูปทุก ๆ ชุด
- ปฏิบัติกับตัวถูกดำเนินการทั้งหกเป็นเลขฐาน -4 และเปลี่ยนรูปทุก ๆ ชุด
- ( ... )
ทำอย่างไรทั้งหมดโดยไม่ต้องวนซ้ำ? ง่าย! เพียงแค่ใช้IEnumerable
และเชื่อมโยงIEnumerator
กับการเรียงลำดับพีชคณิต หลังจากนั้นเราจะใช้ LINQ เพื่อสอบถาม
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() { }
}
ตอนนี้เราอยู่ในธุรกิจ! สิ่งที่เราต้องทำคือระบุตัวอย่างBealOperandGenerator
และค้นหาตัวอย่างของการคาดคะเนของ Beal
ปัญหาใหญ่ของเราต่อไปก็คือว่ามีไม่ได้ดูเหมือนจะเป็นตัวในทางที่จะยกระดับขึ้นสู่อำนาจของการเป็นBigInteger
BigInteger
มีBigInteger.Pow(BigInteger value, int exponent)
และBigInteger.ModPow(BigInteger value, BigInteger exponent, BigInteger modulus)
แต่วิธีที่จะยกระดับBigInteger
เพื่ออำนาจของผู้อื่นBigInteger
, โมดูโลอินฟินิตี้
ช่างเป็นปัญหาที่น่าทึ่งมาก! ดูเหมือนว่ามันถูกสร้างขึ้นเพื่อแก้ไขด้วยIEnumerable
/ IEnumerator
ค้อนของเรา!
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;
}
}
ตอนนี้เรามีวิธีการขยายPow
ที่สามารถเรียกใช้บนBigInteger
และใช้BigInteger
เลขชี้กำลังและไม่มีโมดูลัส
ตกลงเราจะย้อนกลับไป เราจะบอกได้อย่างไรว่ามีตัวอย่างใดBealOperands
เป็นตัวอย่างของการคาดคะเนของ Beal หรือไม่? ดีสองสิ่งต้องเป็นจริง:
- ตัวถูกดำเนินการเมื่อเสียบเข้ากับสูตรนั้นขึ้นที่ด้านบนของหน้าจะต้องสร้างสมการที่แท้จริง
- A, B และ C ต้องไม่มีปัจจัยหลักร่วมกัน (เช่น GCD ของพวกเขาคือ 1)
เรามีสิ่งที่เราต้องตรวจสอบเงื่อนไขก่อน และปรากฎว่าเงื่อนไขที่สองนั้นง่ายกว่ามากในการตรวจสอบ BigInteger
มีGreatestCommonDivisor
วิธีการที่น่ารักซึ่งช่วยให้เราก้าวเท้าเลี่ยงฝันร้ายทั้งหมดของการพยายามที่จะใช้มันโดยไม่ต้องวนซ้ำ
ดังนั้นเราพร้อมที่จะเขียนวิธีการตรวจสอบว่า a BealOperands
เป็นตัวอย่างหรือไม่ ไปที่นี่ ...
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;
}
}
และในที่สุดเราก็สามารถนำทุกสิ่งมารวมกันด้วยวิธีที่ค่อนข้างเรียบMain
:
static class Program
{
static void Main()
{
var bealOperandGenerator = new BealOperandGenerator();
if (bealOperandGenerator.Any(o => o.IsBealsConjectureCounterExample()))
{
Console.WriteLine("IN YOUR FACE, BEAL!");
}
}
}