C #, không có vòng lặp
OK, tôi đã lướt qua một vài trong số các liên kết đó, nhưng thành thật mà nói họ hơi nhàm chán. Tôi không quan tâm đến việc tối ưu hóa địa ngục với bảng băm và không có gì. Tại sao tôi cần phải? Bạn đã có một siêu máy tính chết tiệt!
Chết tiệt, tôi thậm chí không muốn làm phiền với các vòng lặp! Giải pháp này sẽ tuân theo quy tắc không vòng lặp .
Xin lưu ý rằng mã tôi sắp viết không phải là mã tốt hoặc loại mã tôi viết trong đời thực (trong trường hợp bất kỳ nhà tuyển dụng tiềm năng nào tình cờ đọc được mã này). Mã này nhấn mạnh đến tính ngắn gọn và khả năng làm việc trong một bài tường thuật, và coi thường các quy ước và nghi thức và vòng lặp thích hợp, v.v.
Để giải thích những gì tôi đang nói, chúng ta sẽ bắt đầu với một lớp gây sốc với các trường công khai để lưu trữ các toán hạng của phương trình:
class BealOperands
{
public BigInteger A, B, C, x, y, z;
}
OK, chúng ta sẽ bắt đầu với những gì có lẽ là thử thách khó khăn nhất. Chúng ta cần tìm ra một cách để thẩm thấu qua mọi sự kết hợp của các toán hạng đó. Chắc chắn có nhiều cách để làm điều đó hiệu quả hơn là kiểm tra mọi hoán vị, nhưng tôi không thể bận tâm tìm ra chúng. Và tại sao tôi phải? Chúng ta đã có một siêu máy tính chết tiệt!
Đây là thuật toán tôi nghĩ ra. Nó cực kỳ kém hiệu quả, và lặp đi lặp lại cùng một toán hạng, nhưng ai quan tâm? Siêu máy tính!
- Coi sáu toán hạng là số cơ sở-2 và hoán vị qua mọi kết hợp.
- Coi sáu toán hạng là số cơ sở 3 và hoán vị qua mọi kết hợp.
- Coi sáu toán hạng là số cơ sở 4 và hoán vị qua mọi kết hợp.
- (...)
Làm thế nào để làm tất cả điều này mà không có vòng lặp? Dễ dàng! Chỉ cần thực hiện một IEnumerable
và liên quan IEnumerator
để bơm ra hoán vị. Sau đó, chúng tôi sẽ sử dụng LINQ để truy vấn nó.
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() { }
}
Bây giờ chúng tôi đang kinh doanh! Tất cả những gì chúng ta cần làm là liệt kê một ví dụ BealOperandGenerator
và tìm một ví dụ về phỏng đoán của Beal.
Vấn đề lớn tiếp theo của chúng tôi là dường như không có cách tích hợp nào để nâng cao BigInteger
sức mạnh của a BigInteger
. Có BigInteger.Pow(BigInteger value, int exponent)
, và BigInteger.ModPow(BigInteger value, BigInteger exponent, BigInteger modulus)
, nhưng không có phương pháp nào để nâng cao BigInteger
sức mạnh của người khác BigInteger
, vô hạn modulo.
Thật là một móng tay sáng bóng của một vấn đề! Có vẻ như nó đã được thực hiện để được giải quyết bằng IEnumerable
/ IEnumerator
búa của chúng tôi !
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;
}
}
Bây giờ chúng ta đã có một phương thức mở rộng Pow
, có thể được gọi làBigInteger
và mất mộtBigInteger
số mũ và không có mô đun.
OK, hãy lùi lại. Làm thế nào chúng ta có thể biết nếu một cụ thể BealOperands
là một ví dụ về phỏng đoán của Beal? Vâng, hai điều cần phải đúng:
- Các toán hạng, khi được cắm vào công thức đó ở đầu trang, phải tạo thành một phương trình đúng.
- A, B và C KHÔNG phải có thừa số nguyên tố chung (nghĩa là GCD của chúng là 1).
Chúng tôi đã có những gì chúng ta cần kiểm tra điều kiện đầu tiên. Và hóa ra điều kiện thứ hai dễ kiểm tra hơn nhiều so với âm thanh. BigInteger
cung cấp một GreatestCommonDivisor
phương pháp đáng yêu , cho phép chúng ta thuận tiện vượt qua cơn ác mộng cố gắng thực hiện điều đó mà không cần vòng lặp.
Vì vậy, chúng tôi đã sẵn sàng để viết một phương pháp để kiểm tra xem a BealOperands
có phải là một ví dụ không. Ở đây đi ...
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;
}
}
Và cuối cùng chúng ta có thể kết hợp tất cả lại với nhau bằng Main
phương pháp khá lắt léo này:
static class Program
{
static void Main()
{
var bealOperandGenerator = new BealOperandGenerator();
if (bealOperandGenerator.Any(o => o.IsBealsConjectureCounterExample()))
{
Console.WriteLine("IN YOUR FACE, BEAL!");
}
}
}