Frazione per decimale esatto


23

Scrivi un programma o una funzione che ha dato due numeri interi a, b genera una stringa contenente un numero decimale che rappresenta esattamente la frazione a / b .

Se a / b è un numero intero, è sufficiente generare il valore, senza un punto decimale o zero iniziali:

123562375921304812375087183597 / 2777 -> 44494913907563850333124661
81 / 3 -> 27
-6 / 2 -> -3

Se a / b non è intero ma ha una rappresentazione finita in base 10, genera il valore senza zero iniziali o finali (tranne un singolo zero prima del punto):

1 / 2 -> 0.5
3289323463 / -250000000 -> -13.157293852

Infine, se e solo se (quindi no 0.999...) a / b non è un numero intero e non ha una rappresentazione finita, produce la parte finita seguita dalla parte ripetuta tra parentesi. La parte ripetuta deve essere il più piccola possibile e iniziare il prima possibile.

-1 / 3 -> -0.(3)
235 / 14 -> 16.7(857142)
123 / 321 -> 0.(38317757009345794392523364485981308411214953271028037)
355 / 113 -> 3.(1415929203539823008849557522123893805309734513274336283185840707964601769911504424778761061946902654867256637168)

Il tuo programma deve funzionare per tutti gli esempi sopra riportati in meno di 10 secondi su un moderno PC desktop. Vince il programma più piccolo in byte.


@DestructibleWatermelon Questo è possibile in quasi tutte le lingue, compresi i tarp di Turing. (Quelli potrebbero avere difficoltà con il limite di tempo).
Dennis

@DestructibleWatermelon Ho avuto l'impressione che la maggior parte delle lingue stia diventando completa.
orlp

Possiamo tranquillamente supporre che la frazione non sarà simile a: 0.33333333333336333 ...?
brianush1,

2
Sembra un modo prolisso di chiedere soluzioni a PE26 ;)
Conor O'Brien,

1
Generalizzazione di questa domanda ; anche correlati .
Peter Taylor,

Risposte:


3

Perl 6 ,  63 58  50 byte

{->$a,$b {$a~"($b)"x?$b}(|($^a.FatRat/$^b).base-repeating(10))}
{->\a,$b {a~"($b)"x?$b}(|($^a.FatRat/$^b).base-repeating)}
{$/=($^a.FatRat/$^b).base-repeating;$0~"($1)"x?$1}

Provalo

Se non ti interessa che funzionerà solo con denominatori che rientrano in un numero intero a 64 bit, può essere ridotto a soli 43 byte:

{$/=($^a/$^b).base-repeating;$0~"($1)"x?$1}

Allargato:

{
  # store in match variable so that we can
  # use 「$0」 and 「$1」
  $/ = (

    # turn the first value into a FatRat so that
    # it will continue to work for all Int inputs
    $^a.FatRat / $^b

  ).base-repeating;

  # 「$0」 is short for 「$/[0]」 which is the non-repeating part
  $0

  # string concatenated with
  ~

  # string repeat once if $1 is truthy (the repeating part)
  # otherwise it will be an empty Str
  "($1)" x ?$1
}

Il modo in cui hai formattato la tua risposta è confuso. Dovresti rimuovere i tuoi vecchi programmi, perché in questo momento sembra un programma multilinea.
mbomb007,

@ mbomb007 Il motivo principale che ho per pubblicare golf è per il marketing e l'educazione di Perl 6. Quindi lascio le vecchie versioni per mostrare più della lingua. Questo è anche il motivo per cui raramente ne inserisco uno fino a quando non ho una sorta di spiegazione lì dentro. L'ho modificato in modo che i diversi esempi si trovino in blocchi di codice diversi.
Brad Gilbert b2gills

Le vecchie versioni sono sempre visibili nella cronologia delle modifiche del post.
mbomb007,

@ mbomb007 Non se aspetto di postare fino a dopo aver provato diversi modi per scriverlo.
Brad Gilbert b2gills il

Quindi modificane uno ogni 5 minuti.
mbomb007,

8

Python 2, 174 byte

x,y=input()
a=abs(x)
b=abs(y)
r=a%b*10
L=[]
M=''
while~-(r in L):L+=r,;M+=str(r/b);r=r%b*10
i=L.index(r)
t=M[:i]+"(%s)"%M[i:]*(M[i:]>'0')
print"-%d."[x*y>=0:(t>'')+3]%(a/b)+t

Non sono abbastanza convinto della validità di questa risposta, ma ha funzionato per i casi di test sopra e altri casi di test che ho lanciato. Sembra un casino giusto, quindi sono sicuro che ci sia molto spazio per giocare a golf.

La configurazione iniziale accetta valori assoluti di entrambi gli argomenti per garantire che abbiamo a che fare con numeri non negativi (salvando il calcolo del segno per dopo) e delega la parte quoziente del risultato all'aritmetica di precisione arbitraria di Python. La parte frazionaria viene eseguita con l'algoritmo di divisione della scuola elementare fino a quando non avremo una ripetizione nel resto. Quindi osserviamo l'ultima volta che abbiamo visto questa ripetizione per ottenere il punto e costruire la stringa di conseguenza.

Si noti che l'algoritmo in realtà è piuttosto lento a causa indell'operazione O (n) , ma è abbastanza veloce per gli esempi.


5

Lotto, 349 344 byte

@echo off
set/ad=%2,i=%1/d,r=%1%%d
if not %r%==0 set i=%i%.&if %r% leq 0 set/ar=-r&if %i%==0 set i=-0.
set d=%d:-=%
set/ae=d
:g
if %r%==0 echo %i%&exit/b
set/ag=-~!(e%%2)*(!(e%%5)*4+1)
if not %g%==1 set/ae/=g&call:d&goto g
set/as=r
set i=%i%(
:r
call:d
if %r%==%s% echo %i%)&exit/b
goto r
:d
set/ar*=10,n=r/d,r%%=d
set i=%i%%n%

Modifica: 5 byte salvati rimuovendo i caratteri non necessari. "Ungolfed":

@echo off
set /a d = %2
set /a i = %1 / d
set /a r = %1 % d
if not %r%==0 (
    set i=%i%.                  Decimal point is required
    if %r% leq 0 (
        set /a r = -r           Get absolute value of remainder
        if %i%==0 set i=-0.     Fix edge case (-1/3 = 0 remainder -1)
    )
)
set d = %d:-=%                  Get absolute value of divisor
set /a e = d
:g
if %r%==0 echo %i% & exit /b    Finished if there's no remainder
set /a g = gcd(e, 10)           Loop through nonrecurring decimals
if not %g%==1 (
    set /a e /= g
    call :d
    goto g
)
set /a s = r                    Save remainder to know when loop ends
set i=%i%(
:r
call :d
if %r%==%s% echo %i%)&exit/b
goto r
:d                              Add the next decimal place
set /a r *= 10
set /a n = r / d
set /a r %= d
set i=%i%%n%

2
Non ho idea di come funzioni, ma ti lodo per averlo fatto in batch lmao
Alexander -

Sono impressionato dalle capacità di set /a.
Joe,

2

Java, 625 605

Codice golfizzato:

import static java.math.BigInteger.*;
String f(BigInteger a, BigInteger b){BigInteger[]r=a.divideAndRemainder(b);String s=r[0].toString();if(r[1].signum()<0)s="-"+s;if(!ZERO.equals(r[1])){s+='.';List<BigInteger>x=new ArrayList();List<BigInteger>y=new ArrayList();for(BigInteger d=TEN.multiply(r[1].abs());;){BigInteger[]z=d.divideAndRemainder(b.abs());int i=y.indexOf(z[1]);if(i>-1&&i==x.indexOf(z[0])){for(int j=0;j<i;++j)s+=x.get(j);s+='(';for(int j=i;j<x.size();++j)s+=x.get(j);s+=')';break;}x.add(z[0]);y.add(z[1]);if(ZERO.equals(z[1])){for(BigInteger j:x)s+=j;break;}d=TEN.multiply(z[1]);}}return s;}

Nota: conto l'importazione statica come parte della funzione ai fini del golf.

Questa funzione inizia ottenendo il risultato della divisione. Aggiunge la parte integrale e il segno, se necessario. Quindi se c'è un resto, esegue la divisione lunga base 10. Ad ogni passo, esegui la divisione. Memorizza la cifra calcolata e il resto in due elenchi. Se incontriamo di nuovo la stessa cifra e il resto, c'è una porzione ripetuta e sappiamo da quale indice inizia. Il codice aggiunge le cifre (nessuna ripetizione) o le cifre pre-ripetizione, quindi le cifre ripetute racchiuse tra parentesi.

Questo è un po 'grande soprattutto a causa di BigInteger. Se gli ingressi non traboccassero nemmeno a, longallora potrebbe essere un po 'più breve. Tuttavia, mi aspetto che ci siano modi per migliorare questa voce.

Codice non golfato con il metodo principale per il test:

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import static java.math.BigInteger.*;

public class FractionToExactDecimal {

  public static void main(String[] args) {
    // @formatter:off
    String[][] testData = new String[][] {
      { "123562375921304812375087183597", "2777", "44494913907563850333124661" },
      { "81", "3", "27" },
      { "-6", "2", "-3" },
      { "1", "2", "0.5" },
      { "3289323463", "-250000000", "-13.157293852" },
      { "-1", "3", "-0.(3)" },
      { "235", "14", "16.7(857142)" },
      { "123", "321", "0.(38317757009345794392523364485981308411214953271028037)" },
      { "355", "113", "3.(1415929203539823008849557522123893805309734513274336283185840707964601769911504424778761061946902654867256637168)" }
    };
    // @formatter:on

    for (String[] data : testData) {
      System.out.println(data[0] + " / " + data[1]);
      System.out.println("  Expected -> " + data[2]);
      System.out.print("    Actual -> ");
      System.out.println(new FractionToExactDecimal().f(new BigInteger(data[0]), new BigInteger(data[1])));
      System.out.println();
    }
  }

  // Begin golf
  String f(BigInteger a, BigInteger b) {
    BigInteger[] r = a.divideAndRemainder(b);
    String s = r[0].toString();
    if (r[1].signum() < 0) s = "-" + s;
    if (!ZERO.equals(r[1])) {
      s += '.';
      List<BigInteger> x = new ArrayList();
      List<BigInteger> y = new ArrayList();
      for (BigInteger d = TEN.multiply(r[1].abs());;) {
        BigInteger[] z = d.divideAndRemainder(b.abs());
        int i = y.indexOf(z[1]);
        if (i > -1 && i == x.indexOf(z[0])) {
          for (int j = 0; j < i; ++j)
            s += x.get(j);
          s += '(';
          for (int j = i; j < x.size(); ++j)
            s += x.get(j);
          s += ')';
          break;
        }
        x.add(z[0]);
        y.add(z[1]);
        if (ZERO.equals(z[1])) {
          for (BigInteger j : x)
            s += j;
          break;
        }
        d = TEN.multiply(z[1]);
      }
    }
    return s;
  }
  // End golf
}

Uscita del programma:

123562375921304812375087183597 / 2777
  Expected -> 44494913907563850333124661
    Actual -> 44494913907563850333124661

81 / 3
  Expected -> 27
    Actual -> 27

-6 / 2
  Expected -> -3
    Actual -> -3

1 / 2
  Expected -> 0.5
    Actual -> 0.5

3289323463 / -250000000
  Expected -> -13.157293852
    Actual -> -13.157293852

-1 / 3
  Expected -> -0.(3)
    Actual -> -0.(3)

235 / 14
  Expected -> 16.7(857142)
    Actual -> 16.7(857142)

123 / 321
  Expected -> 0.(38317757009345794392523364485981308411214953271028037)
    Actual -> 0.(38317757009345794392523364485981308411214953271028037)

355 / 113
  Expected -> 3.(1415929203539823008849557522123893805309734513274336283185840707964601769911504424778761061946902654867256637168)
    Actual -> 3.(1415929203539823008849557522123893805309734513274336283185840707964601769911504424778761061946902654867256637168)

Bello! Penso che puoi salvare qualche byte rendendo questa una funzione che restituisce una stringa e rimuovendo quello spazio a, BigInteger. Penso anche che potresti alias BigInteger.TENe BigInteger.ZERO.
FryAmTheEggman,

@FryAmTheEggman grazie, non mi ero reso conto che l'importazione statica salvasse spazio sui riferimenti più dettagliati. Lo fa. Ho anche trovato alcune altre cose che mi mancavano, come while (true)-> for (;;)che mi hanno anche permesso di mettere roba fornell'inizializzatore, salvando un altro byte.

Innanzitutto, che ne dici di estendere BigInteger? In secondo luogo, un resto ripetuto è sufficiente per mostrare che si ripete; se si limita l'input a int, è possibile utilizzare un int [] con il resto come indice e l'indice come valore, se ciò ha senso.
JollyJoker

@JollyJoker estendere BigInteger richiederebbe di scrivere un'intera classe per cercare di risparmiare spazio, e dubito seriamente che il compromesso funzionerebbe. Inoltre, non posso limitare l'input. Comunque, ci sono otto istanze del testo BigIntegernel mio codice e non vedo come l'aggiunta di altro codice per ridurli a un singolo nome di classe di caratteri ripagherà. E sicuramente aggiungere codice per gestire int[](che BigInteger già fa internamente) non farà che gonfiare la mia risposta.

@JollyJoker vale anche la pena ricordare che, a meno che non ignori tutti i BigInteger metodi che chiamo per restituire un'istanza della sottoclasse, dovrò aggiungere diversi cast che gonfiano ulteriormente il codice. Oltre ai byte sprecati per l'overhead di una sottoclasse, ciò aumenterebbe sicuramente la dimensione del codice.

1

PHP, 277 byte

list(,$n,$d)=$argv;$a[]=$n;$n-=$d*$r[]=$n/$d^0;!$n?:$r[]=".";while($n&&!$t){$n*=10;$n-=$d*$r[]=$n/$d^0;$t=in_array($n%=$d,$a);$a[]=$n;}if($t){$l=count($a)-($p=array_search(end($a),$a));echo join(array_slice($r,0,2+$p))."(".join(array_slice($r,2+$p,$l)).")";}else echo join($r);

0

Mathematica 198 byte

i=Integer;t=ToString;a_~h~b_:=f[a/b];f@q_i:= t@q;
f@q_:=""<>{t@IntegerPart[q],".",RealDigits[FractionalPart[q]][[1]]//.{{x___,{k__i}}:> {x,"("<>(t/@{k})<>")"},{x__i,j___String}:>""<> {""<>t/@{x},j}}}

UnGolfed

(* hand over quotient of a, b to function f *)
h[a_, b_] := f[a/b];

(* if the quotient is an integer, return it as a string *)
f[q_Integer] := ToString@q;

(* otherwise, return the integer part, followed by a decimal point ...*)
f[q_] := "" <> {ToString@IntegerPart[q], ".", 

   (* replacing the repeating part (if it exists) between parentheses *)
   RealDigits[FractionalPart[q]][[1]] //. {{x___, {i__Integer}} :> {x, "(" <>(ToString /@ {i}) <> ")"},

   (* and the non-repeating part (if it exists) without parentheses *)
   {x__Integer, i___String} :> "" <> {"" <> ToString /@ {x}, i}}}

test

h @@@ {{81, 3}, {-81, 3}, {1, 4}, {-13, 3}, {19, 7}, {3289323463, 25000}, {235, 14}, {1325, 14}}

{"27", "-27", "0.25", "-4. (3)", "2. (714285)", "131572.93852", "16.7 (857142)", "94.6 (428571)"}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.