Phân số cho số thập phân chính xác


23

Viết chương trình hoặc hàm cho hai số nguyên a, b xuất ra một chuỗi chứa số thập phân thể hiện chính xác phân số a / b .

Nếu a / b là số nguyên, chỉ cần xuất giá trị, không có dấu thập phân hoặc số 0 đứng đầu:

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

Nếu a / b không phải là số nguyên nhưng có biểu diễn hữu hạn trong cơ sở 10, hãy xuất giá trị mà không có các số 0 đứng đầu hoặc dấu (trừ một số 0 duy nhất trước dấu chấm):

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

Cuối cùng, nếu và chỉ khi (vì vậy không 0.999...) a / b không phải là số nguyên và không có biểu diễn hữu hạn, hãy xuất phần hữu hạn theo sau là phần lặp lại trong ngoặc đơn. Phần lặp lại phải càng nhỏ càng tốt, và bắt đầu càng sớm càng tốt.

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

Chương trình của bạn phải hoạt động cho tất cả các ví dụ trên trong dưới 10 giây trên máy tính để bàn hiện đại. Chương trình nhỏ nhất trong byte thắng.


@DeststallibleWateriwi Điều này có thể có trong hầu hết các ngôn ngữ, bao gồm cả Turing tarpits. (Tuy nhiên, những người đó có thể vật lộn với giới hạn thời gian.)
Dennis

@DeststallibleWateriwi Tôi có ấn tượng rằng hầu hết các ngôn ngữ đều được hoàn thiện.
orlp

Chúng ta có thể giả định một cách an toàn phân số sẽ không giống như: 0.33333333333336333 ...?
brianush1

2
Đây có vẻ như là một cách dài dòng để yêu cầu các giải pháp cho PE26 ;)
Conor O'Brien

Câu trả lời:


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}

Kiểm tra nó

Nếu bạn không quan tâm rằng nó sẽ chỉ hoạt động với các mẫu số phù hợp với số nguyên 64 bit, nó có thể được rút ngắn chỉ còn 43 byte:

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

Mở rộng:

{
  # 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
}

Cách bạn định dạng câu trả lời của bạn là khó hiểu. Bạn nên loại bỏ các chương trình cũ của bạn, bởi vì ngay bây giờ nó trông giống như một chương trình nhiều dòng.
mbomb007

@ mbomb007 Lý do chính tôi có để đăng golf là để tiếp thị và giáo dục Perl 6. Vì vậy, tôi để các phiên bản cũ để hiển thị thêm ngôn ngữ. Đó cũng là lý do tại sao tôi hiếm khi đăng một bài cho đến khi tôi có một số lời giải thích trong đó. Tôi đã thay đổi nó để các ví dụ khác nhau nằm trong các khối mã khác nhau.
Brad Gilbert b2gills

Các phiên bản cũ luôn hiển thị trong lịch sử chỉnh sửa của bài đăng.
mbomb007

@ mbomb007 Không phải nếu tôi chờ đợi để đăng cho đến khi thử một vài cách khác nhau để viết nó.
Brad Gilbert b2gills

Sau đó chỉ cần chỉnh sửa một trong mỗi 5 phút.
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

Tôi không hoàn toàn bị thuyết phục về tính hợp lệ của câu trả lời này, nhưng nó đã hoạt động cho các trường hợp thử nghiệm ở trên và các trường hợp thử nghiệm khác mà tôi đã ném vào nó. Nó trông giống như một mớ hỗn độn, vì vậy tôi chắc chắn có nhiều chỗ để chơi gôn.

Thiết lập ban đầu lấy các giá trị tuyệt đối của cả hai đối số để đảm bảo rằng chúng ta xử lý các số không âm (lưu tính toán ký hiệu cho lần sau) và ủy thác phần thương số của kết quả cho số học chính xác tùy ý của Python. Phần phân số được thực hiện với thuật toán phân chia trường học cho đến khi chúng ta lặp lại trong phần còn lại. Sau đó, chúng tôi tìm kiếm khi lần cuối cùng nhìn thấy điều này lặp lại để có được khoảng thời gian và xây dựng chuỗi phù hợp.

Lưu ý rằng thuật toán thực sự khá chậm do inhoạt động O (n) , nhưng nó đủ nhanh cho các ví dụ.


5

Mẻ 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%

Chỉnh sửa: Đã lưu 5 byte bằng cách xóa các ký tự không cần thiết. "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
Tôi không biết làm thế nào bất kỳ thứ này hoạt động, nhưng tôi khen bạn đã làm nó trong đợt lmao
Alexander - Tái lập Monica

Tôi ấn tượng với khả năng của set /a.
Joe

2

Java, 625 605

Mã đánh gôn:

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;}

Lưu ý: Tôi tính việc nhập tĩnh là một phần của chức năng cho mục đích chơi gôn.

Hàm này bắt đầu bằng cách lấy kết quả chia. Nó thêm phần không thể thiếu và ký, nếu cần thiết. Sau đó, nếu có một phần còn lại, nó thực hiện phân chia cơ sở 10 dài. Ở mỗi bước, thực hiện việc phân chia. Lưu trữ chữ số tính toán và phần còn lại trong hai danh sách. Nếu chúng ta gặp lại cùng một chữ số và phần còn lại, có một phần lặp lại và chúng ta biết nó bắt đầu từ chỉ mục nào. Mã hoặc thêm các chữ số (không lặp lại) hoặc các chữ số lặp lại trước, sau đó các chữ số lặp lại được đặt trong ngoặc đơn.

Đây là một chút lớn chủ yếu là vì BigInteger. Nếu đầu vào không tràn thậm chílong thì nó có thể ngắn hơn một chút. Tuy nhiên, tôi hy vọng có nhiều cách để cải thiện mục này.

Mã Ungolfed với phương thức chính để thử nghiệm:

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
}

Đầu ra chương trình:

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)

Tốt đẹp! Tôi nghĩ rằng bạn có thể lưu một vài byte bằng cách biến đây thành một hàm trả về một chuỗi và bằng cách loại bỏ một khoảng trắng đó a, BigInteger. Tôi cũng nghĩ rằng bạn có thể bí danh BigInteger.TENBigInteger.ZERO.
FryAmTheEggman

@FryAmTheEggman cảm ơn, tôi đã không nhận ra không gian lưu trữ nhập tĩnh qua các tham chiếu dài dòng hơn. Nó làm. Tôi cũng tìm thấy một vài thứ khác mà tôi đã bỏ lỡ, chẳng hạn như while (true)-> for (;;)cũng cho phép tôi đặt công cụ vào trình forkhởi tạo, lưu một byte khác.

Đầu tiên, làm thế nào về việc mở rộng BigInteger? Thứ hai, một phần còn lại lặp đi lặp lại là đủ để cho thấy nó lặp lại; nếu bạn giới hạn đầu vào là int, bạn có thể sử dụng int [] với phần còn lại là chỉ mục và chỉ mục là giá trị, nếu điều đó có ý nghĩa.
JollyJoker

@JollyJoker mở rộng BigInteger sẽ yêu cầu viết cả một lớp để cố gắng tiết kiệm không gian và tôi thực sự nghi ngờ sự đánh đổi sẽ có hiệu quả. Thêm vào đó, tôi không thể hạn chế đầu vào. Dù sao, có tám phiên bản văn bản BigIntegertrong mã của tôi và tôi không thấy việc thêm nhiều mã để thu nhỏ chúng vào một tên lớp ký tự sẽ trả hết. Và chắc chắn việc thêm mã để đối phó int[](điều mà BigInteger đã làm trong nội bộ) sẽ chỉ làm hỏng câu trả lời của tôi.

@JollyJoker cũng cần đề cập rằng trừ khi tôi ghi đè mọi BigInteger phương thức tôi gọi để trả về một thể hiện của lớp con, tôi sẽ cần thêm một số phôi để làm tăng thêm mã. Trên đầu các byte bị lãng phí cho chi phí hoạt động của lớp con, điều đó chắc chắn sẽ làm tăng kích thước mã.

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

Toán học 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}}}

Vô duyên

(* 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}}}

Xét nghiệm

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)"}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.