C #, без петель
Добре, я пропустив пару цих посилань, але якщо чесно вони були трохи нудні. Мені не цікаво оптимізувати хеш-сюди за допомогою хеш-таблиць і чогось іншого. Навіщо мені це потрібно? У тебе проклятий суперкомп'ютер!
Чорт, я навіть не хочу морочитися з петлями! Це рішення буде дотримуватися правила без циклу .
Зверніть увагу, що код, який я збираюся написати, це не гарний код або тип коду, який я б написав у реальному житті (на випадок, якщо будь-які потенційні роботодавці прочитають це). Цей код підкреслює стислість та вміння працювати в оповіданні та демефазує належні умовності та ритуали, петлі тощо.
Щоб продемонструвати те, про що я говорю, ми почнемо з шокуючого класу з публічними полями для зберігання операндів рівняння:
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
і знайти контрприклад з Концепції Біла.
Наступна наша велика проблема полягає в тому, що, здається, не існує вбудованого способу підняти BigInteger
силу до сили BigInteger
. Існує BigInteger.Pow(BigInteger value, int exponent)
і BigInteger.ModPow(BigInteger value, BigInteger exponent, BigInteger modulus)
, але немає способу підняти a 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
, який можна викликати на a BigInteger
і приймає aBigInteger
показник, а не модуль.
Добре, давайте відступимо. Як ми можемо визначити, чи є конкретний BealOperands
контрприклад задуму Біла? Дві речі повинні бути правдивими:
- Операнди, підключаючись до цієї формули вгорі сторінки, повинні утворювати справжнє рівняння.
- A, B і C НЕ повинні мати загального основного фактора (тобто їх GCD дорівнює 1).
У нас є те, що нам потрібно для перевірки першої умови. І виявляється, другу умову перевірити набагато простіше, ніж це звучить. BigInteger
надає чудовий GreatestCommonDivisor
метод, який дозволяє нам зручно проходити весь кошмар намагання здійснити це без циклів.
Тож ми готові написати метод, щоб перевірити, чи 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!");
}
}
}