分数精确到小数


23

编写一个给定两个整数a,b的程序或函数,输出一个字符串该字符串包含一个十进制数字,精确地表示分数a / b

如果a / b是整数,则只需输出该值,不带小数点或前导零:

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

如果a / b不是整数,但以10为底的有限表示形式,则输出该值时不带前导或尾随零(点之前的单个零除外):

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

最后,当且仅当(so no 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.33333333333336333 ...吗?
brianush1年

2
这似乎是寻求PE26解决方案的漫长方式;)
Conor O'Brien

Answers:


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

@ mbomb007我发布高尔夫球的主要原因是为了市场营销和对Perl 6的教育。因此,我保留了旧版本以显示更多语言。这就是为什么我很少在其中发表某种解释之前发布的原因。我已经对其进行了更改,以便不同的示例位于不同的代码块中。
布拉德·吉尔伯特b2gills

旧版本在帖子的编辑历史记录中始终可见。
mbomb007'7

@ mbomb007如果我等到尝试几种不同的编写方式后才发帖,则不会。
布拉德·吉尔伯特b2gills

然后,每5分钟编辑一次。
mbomb007'7

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

批处理,349344字节

@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个字节。“无高尔夫球”:

@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
亚历山大–恢复莫妮卡,

的功能给我留下了深刻的印象set /a

2

Java 625 605

高尔夫代码:

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。如果输入没有溢出甚至long则可能会短一些。不过,我希望有一些方法可以改善此条目。

具有主要测试方法的无代码的代码:

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.TENBigInteger.ZERO
FryAmTheEggman'8

@FryAmTheEggman谢谢,我没有意识到静态导入节省了更多详细引用的空间。是的 我还发现了我错过的其他一些东西,例如while (true)-> for (;;),这也使我可以将东西放入for初始化程序中,从而节省了另一个字节。

首先,如何扩展BigInteger?其次,重复的余数足以表明其重复。如果将输入限制为int,则可以使用int [],将余数作为索引,将index作为值,如果有道理。
JollyJoker

扩展BigInteger的@JollyJoker要求编写一个整个类以节省空间,我严重怀疑这种折衷是否可行。另外,我不能限制输入。无论如何,BigInteger我的代码中有8个文本实例,而且我看不出添加更多代码将它们缩小为单个字符类名称的效果如何。当然,添加要处理的代码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}}}

松散

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.