C #, sem loops
OK, eu passei por alguns desses links, mas para ser sincero, eles eram um pouco chatos. Não estou interessado em otimizar o inferno com tabelas de hash e outros enfeites. Por que eu preciso? Você tem um maldito supercomputador!
Inferno, eu nem quero me preocupar com loops! Esta solução seguirá a regra de no-loops .
Observe que o código que estou prestes a escrever não é um código bom ou o tipo de código que eu escreveria na vida real (caso algum empregador em potencial leia isso). Esse código enfatiza a brevidade e a capacidade de trabalhar em uma narrativa e enfatiza as convenções, rituais e loops adequados e assim por diante.
Para demonstrar do que estou falando, começaremos com uma classe chocante com campos públicos para armazenar os operandos da equação:
class BealOperands
{
public BigInteger A, B, C, x, y, z;
}
OK, começaremos com o que provavelmente é o desafio mais difícil. Precisamos descobrir uma maneira de permutar todas as combinações desses operandos. Sem dúvida, existem maneiras de fazê-lo com mais eficiência do que verificar todas as permutações, mas não posso me incomodar em descobri-las. E por que eu deveria? Temos um maldito supercomputador!
Aqui está o algoritmo que eu criei. É incrivelmente ineficiente e repassa repetidamente os mesmos operandos, mas quem se importa? Supercomputador!
- Trate os seis operandos como um número de base 2 e permeie todas as combinações.
- Trate os seis operandos como um número base-3 e permeie todas as combinações.
- Trate os seis operandos como um número base-4 e permeie todas as combinações.
- (...)
Como fazer tudo isso sem loops? Fácil! Basta implementar um IEnumerablee associado IEnumeratorpara bombear as permutações. Mais tarde, usaremos o LINQ para consultá-lo.
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() { }
}
Agora estamos no negócio! Tudo o que precisamos fazer é enumerar uma instância BealOperandGeneratore encontrar um contra-exemplo da conjectura de Beal.
Nosso próximo grande problema é que não parece haver uma maneira embutida de elevar BigIntegera à potência de a BigInteger. Existe BigInteger.Pow(BigInteger value, int exponent), e BigInteger.ModPow(BigInteger value, BigInteger exponent, BigInteger modulus), mas não existe, um método para elevar um BigInteger, ao poder de outro BigInteger, módulo infinito.
Que prego brilhante de problema! Parece que foi feito para ser resolvido com o nosso IEnumerable/ IEnumeratorhammer!
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;
}
}
Agora temos um método de extensão Pow, que pode ser chamado em a BigInteger, e leva umBigInteger expoente e nenhum módulo.
OK, vamos voltar. Como podemos saber se um particular BealOperandsé um contra-exemplo da conjectura de Beal? Bem, duas coisas precisam ser verdadeiras:
- Os operandos, quando conectados a essa fórmula na parte superior da página, devem formar uma equação verdadeira.
- A, B e C NÃO devem ter um fator primo comum (ou seja, seu MDC é 1).
Temos o que precisamos para verificar a primeira condição. E acontece que a segunda condição é muito mais fácil de verificar do que parece. BigIntegerfornece um GreatestCommonDivisormétodo adorável , que permite evitar convenientemente todo o pesadelo de tentar implementá-lo sem loops.
Portanto, estamos prontos para escrever um método para verificar se a BealOperandsé um contra-exemplo. Aqui vai ...
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;
}
}
E, finalmente, podemos reunir tudo com esse Mainmétodo bastante liso :
static class Program
{
static void Main()
{
var bealOperandGenerator = new BealOperandGenerator();
if (bealOperandGenerator.Any(o => o.IsBealsConjectureCounterExample()))
{
Console.WriteLine("IN YOUR FACE, BEAL!");
}
}
}