เศษส่วนเป็นทศนิยมที่แน่นอน


23

เขียนโปรแกรมหรือฟังก์ชั่นที่ได้รับสองจำนวนเต็มA, B outputs สตริงที่มีตัวเลขทศนิยมที่เป็นตัวแทนของเศษA / B ว่า

หากa / bเป็นจำนวนเต็มเพียงแค่ส่งออกค่าโดยไม่มีจุดทศนิยมหรือศูนย์นำหน้า:

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

หากa / bไม่ใช่จำนวนเต็ม แต่มีการแทนค่า จำกัด ในฐาน 10 ให้ส่งออกค่าโดยไม่มีศูนย์นำหน้าหรือต่อท้าย (ยกเว้นศูนย์เดียวก่อนจุด):

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

ในที่สุดถ้าหาก (ดังนั้นไม่0.999...) a / bไม่ใช่จำนวนเต็มและไม่มีการแทน จำกัด ให้เอาท์พุทส่วน จำกัด ตามด้วยส่วนซ้ำในวงเล็บ ส่วนที่ทำซ้ำจะต้องมีขนาดเล็กที่สุดและเริ่มต้นให้เร็วที่สุด

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

โปรแกรมของคุณจะต้องใช้งานได้กับตัวอย่างข้างต้นทั้งหมดภายใน 10 วินาทีบนเดสก์ท็อปพีซีที่ทันสมัย โปรแกรมที่เล็กที่สุดในหน่วยไบต์ชนะ


@DestructibleWatermelon นี่เป็นไปได้ในทุกภาษารวมถึง Turing tarpits (สิ่งเหล่านั้นอาจต่อสู้กับการ จำกัด เวลา)
เดนนิส

@DestructibleWatermelon ฉันรู้สึกว่าภาษาส่วนใหญ่จะสมบูรณ์
orlp

เราสามารถสรุปได้อย่างปลอดภัยหรือไม่ว่า 0.333333333336363 ...
brianush1

2
ดูเหมือนจะเป็นหนทางที่ยืดยาวในการขอคำตอบต่อPE26 ;)
Conor O'Brien

1
ลักษณะทั่วไปของคำถามนี้ ; นอกจากนี้ยังเกี่ยวข้องกับ
Peter Taylor

คำตอบ:


3

Perl 6 ,  63 58  50 ไบต์

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

ทดสอบมัน

หากคุณไม่สนใจว่ามันจะทำงานกับตัวส่วนที่พอดีกับจำนวนเต็ม 64 บิตมันสามารถย่อให้เหลือเพียง 43 ไบต์:

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

ขยาย:

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

วิธีที่คุณจัดรูปแบบคำตอบของคุณสับสน คุณควรลบโปรแกรมเก่าออกเพราะตอนนี้ดูเหมือนโปรแกรมหลายบรรทัด
mbomb007

@ mbomb007 เหตุผลหลักที่ฉันมีสำหรับการโพสต์กอล์ฟเพื่อการตลาดและการศึกษาของ Perl 6 ดังนั้นฉันจึงปล่อยรุ่นเก่าไว้เพื่อแสดงภาษามากขึ้น นั่นเป็นสาเหตุที่ฉันไม่ค่อยโพสต์จนกว่าจะมีคำอธิบายในนั้น ฉันได้ทำการเปลี่ยนแปลงเพื่อให้ตัวอย่างที่แตกต่างกันอยู่ในบล็อคโค้ดที่แตกต่างกัน
Brad Gilbert b2gills

เวอร์ชันเก่าสามารถมองเห็นได้เสมอในประวัติการแก้ไขโพสต์
mbomb007

@ mbomb007 ไม่ใช่ถ้าฉันรอที่จะโพสต์จนกว่าหลังจากลองหลายวิธีในการเขียน
แบรดกิลเบิร์ต b2gills

จากนั้นแก้ไขเพียงหนึ่งในทุก ๆ 5 นาที
mbomb007

8

Python 2, 174 ไบต์

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

ฉันไม่ค่อยมั่นใจเกี่ยวกับความถูกต้องของคำตอบนี้ แต่มันใช้ได้กับกรณีทดสอบด้านบนและกรณีทดสอบอื่น ๆ ที่ฉันเคยทำมา ดูเหมือนว่าจะเป็นเรื่องที่ถูกต้องดังนั้นฉันมั่นใจว่ามีพื้นที่มากมายสำหรับการเล่นกอล์ฟ

การตั้งค่าเริ่มต้นใช้ค่าสัมบูรณ์ของอาร์กิวเมนต์ทั้งสองเพื่อให้แน่ใจว่าเรากำลังจัดการกับตัวเลขที่ไม่ติดลบ (บันทึกการคำนวณเครื่องหมายสำหรับภายหลัง) และมอบหมายส่วนที่หารของผลลัพธ์ให้กับเลขคณิตความแม่นยำตามอำเภอใจของ Python ส่วนที่เป็นเศษส่วนจะทำด้วยอัลกอริทึมการแบ่งระดับชั้นมัธยมจนกระทั่งเราทำซ้ำในส่วนที่เหลือ จากนั้นเราจะค้นหาเมื่อเราเห็นการทำซ้ำครั้งล่าสุดเพื่อให้ได้ระยะเวลาและสร้างสตริงตามนั้น

โปรดทราบว่าจริงๆแล้วอัลกอริทึมค่อนข้างช้าเนื่องจากการดำเนินการ O (n) inแต่มันเร็วพอสำหรับตัวอย่าง


5

แบตช์349 344 ไบต์

@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%

แก้ไข: บันทึก 5 ไบต์โดยลบอักขระที่ไม่จำเป็นออก "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
ฉันไม่รู้ว่ามันทำงานอย่างไร แต่ฉันขอชมเชยให้คุณทำมันเป็นชุด lmao
Alexander - Reinstate Monica

set /aผมประทับใจกับความสามารถของ
โจ

2

Java, 625 605

รหัส Golfed:

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

หมายเหตุ: ฉันนับการนำเข้าคงที่เป็นส่วนหนึ่งของฟังก์ชั่นเพื่อการเล่นกอล์ฟ

ฟังก์ชั่นนี้เริ่มต้นด้วยการรับผลการหาร มันจะเพิ่มส่วนสำคัญและเครื่องหมายถ้าจำเป็น จากนั้นหากมีส่วนที่เหลือจะดำเนินการหารฐานยาว 10 ในแต่ละขั้นตอนทำการแบ่ง เก็บตัวเลขที่คำนวณได้และส่วนที่เหลือในสองรายการ หากเราพบตัวเลขเดียวกันและส่วนที่เหลืออีกครั้งจะมีส่วนที่ซ้ำกันและเรารู้ว่าดัชนีเริ่มต้นที่ รหัสจะเพิ่มตัวเลข (ไม่ต้องทำซ้ำ) หรือตัวเลขที่มีการทำซ้ำก่อนหน้าจากนั้นตัวเลขที่ซ้ำกันจะอยู่ในวงเล็บ

BigIntegerนี้เป็นใหญ่บิตส่วนใหญ่เป็นเพราะ หากอินพุตไม่ล้นแม้แต่ a longก็อาจสั้นลงเล็กน้อย ถึงกระนั้นฉันคาดหวังว่าจะมีวิธีในการปรับปรุงรายการนี้

รหัส Ungolfed ด้วยวิธีการหลักสำหรับการทดสอบ:

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
}

ผลลัพธ์ของโปรแกรม:

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)

ดี! ฉันคิดว่าคุณสามารถบันทึกได้สองสามไบต์ด้วยการทำให้ฟังก์ชั่นนี้คืนค่าสตริงและลบหนึ่งช่องว่างa, BigIntegerออก ผมยังคิดว่าคุณสามารถนามแฝงและBigInteger.TEN BigInteger.ZERO
FryAmTheEggman

@FryAmTheEggman ขอบคุณฉันไม่ได้ตระหนักถึงการนำเข้าพื้นที่ที่บันทึกไว้ในการอ้างอิง verbose มากขึ้น มันทำ ฉันพบสิ่งอื่นอีกสองสามอย่างที่ฉันพลาดไปเช่นwhile (true)-> for (;;)ซึ่งอนุญาตให้ฉันใส่สิ่งต่าง ๆ ในเครื่องมือforเริ่มต้นซึ่งช่วยประหยัดอีกไบต์

ขั้นแรกให้ขยาย BigInteger เป็นอย่างไร? ประการที่สองส่วนที่เหลือซ้ำจะเพียงพอที่จะแสดงซ้ำ หากคุณ จำกัด อินพุตให้เป็น int คุณสามารถใช้ int [] กับส่วนที่เหลือเป็นดัชนีและดัชนีเป็นค่าหากเหมาะสม
JollyJoker

@ JollyJoker ขยาย BigInteger จะต้องเขียนทั้งชั้นเพื่อพยายามประหยัดพื้นที่และฉันก็สงสัยว่าการแลกเปลี่ยนจะได้ผล นอกจากนี้ฉันไม่สามารถจำกัด อินพุต อย่างไรก็ตามมีแปดข้อความBigIntegerในรหัสของฉันและฉันไม่เห็นวิธีการเพิ่มรหัสเพิ่มเติมเพื่อย่อให้เป็นชื่อคลาสอักขระเดียวจะชำระ และแน่นอนว่าการเพิ่มรหัสเพื่อจัดการกับint[](ซึ่ง BigInteger ทำอยู่แล้วภายใน) จะขยายคำตอบของฉันเท่านั้น

@ JollyJoker มันก็คุ้มค่าที่จะกล่าวถึงเว้นแต่ว่าฉันจะแทนที่ทุก BigIntegerวิธีที่ฉันเรียกเพื่อส่งคืนอินสแตนซ์ของคลาสย่อยฉันจะต้องเพิ่มการปลดเปลื้องหลายครั้งซึ่งจะขยายโค้ดเพิ่มเติม ด้านบนของไบต์ที่สูญเปล่าสำหรับค่าใช้จ่ายของคลาสย่อยที่จะเพิ่มขนาดรหัสอย่างแน่นอน

1

PHP, 277 ไบต์

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 ไบต์

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

การทดสอบ

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.