임의 정밀 정수과


16

우리는 임의로 큰 정수에 대한 나누기를 구현할 것입니다.

이것은 입니다.

이 작업은 임의의 정밀 정수와 나눗셈을 구현하는 프로그램이나 함수를 작성하는 것입니다.

이 작업을 매우 쉽게 해줄 수있는 많은 것들이 허용되지 않습니다 . 사양을 반드시 읽어 보시기 바랍니다 .

입력

입력으로 두 가지가 제공됩니다.

  1. 밑이 10 자리 인 문자열을 호출합니다 n.
  2. 기본 10 자리의 다른 문자열 m

n>m>00으로 나누도록 요청받지 않을 것임을 의미 한다고 가정하자 .

산출

두 개의 숫자를 출력하며 Q, R여기서 m * Q + R = n0 <= R <m

명세서

  • 제출은 임의로 큰 정수 (사용 가능한 메모리로 제한됨)에 대해 작동해야합니다.

  • 당신은 하지 않을 수 있습니다 외부 라이브러리를 사용합니다. i / o 용 외부 라이브러리가 필요한 경우 내장 라이브러리로 취급 할 수 있습니다. (iostream 등과 같은 것을 봅니다).

  • 언어에 내장 된 언어가이를 사소한 경우 사용할 수 없습니다 . 여기에는 임의의 정밀 정수를 처리 할 수있는 내장 유형이 포함되지만 이에 국한되지는 않습니다.

  • 어떤 이유로 언어가 기본적으로 임의의 정밀 정수를 사용하는 경우이 기능을 사용하여 일반적으로 64 비트로 저장할 수없는 정수를 나타낼 수 없습니다.

  • 입력과 출력은 10 진수 여야 합니다. 숫자를 메모리에 저장하는 방법이나 그에 대한 산술을 수행하는 방법은 중요하지 않지만 i / o는 10이됩니다.

  • 결과를 출력하는 데 15 초가 있습니다. 이것은 반복 뺄셈을 금지하기위한 것입니다.

  • 여기서 목표는 실제로 임의의 정밀 정수를 구현하는 것입니다. 어떤 이유로 챌린지 사양을 준수하고 구현하지 않고 성공적으로 수행 할 수 있다면, 나는 당신에게 좋을 것 같습니다.

테스트 사례

  1. 이 경우 입력은 39입니다! 그리고 30!

입력

n = 20397882081197443358640281739902897356800000000 
m = 265252859812191058636308480000000

산출

Q = 76899763100160
R = 0
  1. n는 모든 계승의 합에 최대 50을 더한 값에 1을 더한 값입니다. 1 m은 최대 20까지입니다.

입력

n = 31035053229546199656252032972759319953190362094566672920420940313
m = 1234567891011121314151617181920

산출

q = 25138393324103249083146424239449429
r = 62459510197626865203087816633
  1. n205입니다! + 200 !. mPeterTaylor가 샌드 박스에 게시 한 내용을 찢어서 흘리게 한 눈물입니다.

입력

n = 271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000
m = 247

산출

q = 1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000
r = 0;

아마 어느 시점에서 더 많은 테스트 사례를 추가 할 것입니다.

관련

관련성이 있지만 실제로는 그렇지 않습니다.


IO 라이브러리는 외부 라이브러리로 계산됩니까?
Johnson Steward

@JohnsonSteward 그게 무슨 뜻인지 잘 모르겠어? 기본적으로 "yes"로 설정하지만 명확하게 설명 할 수 있습니까?
Liam

@ JohnsonSteward 잘 당신이 IOing에 달려 있다고 생각합니까? 코드 / 코드 라이브러리입니까?
Ashwin Gupta

1
음수가 허용됩니까?
The Constructor

2
@TheConstructor : 규칙에서 : "n> m> 0이라고 가정"하므로 아니오, 음수는 허용되지 않습니다.
nimi

답변:


4

파이썬 2, 427 바이트

b=S=lambda l:sorted(l)[::-1]
A=lambda a,b,o=0:A(a^b,{n+1for n in[b&a,b-a][o]},o)if b else a
M=lambda a,*b:reduce(A,({n+m for n in a}for m in b))
def D(a,b):
 q=a-a
 while b<=S(a):n=max(a)-b[0];n-=S(M(b,n))>S(a);q|={n};a=A(a,M(b,n),1)
 return q,a
exec"a=b;b=[]\nfor d in raw_input():b=A(M(b,3,1),{i for i in range(4)if int(d)>>i&1})\n"*2
for n in D(a,S(b)):
 s=''
 while n:n,d=D(n,[3,1]);s=`sum(2**i for i in d)`+s
 print s or 0

STDIN을 통해 입력을 각 행마다 별도의 행으로 읽고 결과를 STDOUT에 인쇄합니다.

설명

정수를 숫자의 배열로 나타내는 대신 각 정수를 이진 표현에서 "온"비트 세트로 나타냅니다. 즉, 정수 N 의 이진 표현 (1)와 동일한 비트 인덱스의 집합으로 표현되는 N . 예를 들어, 2 진수 10, 1010은 {1, 3} 세트로 표시됩니다. 이 표현을 통해 파이썬의 set 연산을 사용하여 일부 산술 연산을 간결하게 표현할 수 있습니다.

두 세트를 더하기 위해, 우리는 (재귀 적으로) 그들의 대칭 적 차이의 합과 후속 정수 세트를 교차점 (집합 캐리에 해당하므로 결국 빈 세트가 됨)을 취합니다. .) 유사하게, 두 세트를 빼기 위해, 우리는 (재귀 적으로) 그들의 대칭 적 차이의 차를 취하고 그 다음의 정수 세트를 그들의 (세트) 차이 (집합 차용에 해당하므로 결국 빈 세트가 됨) 이 두 가지 작업의 유사성으로 인해 단일 함수 ( A) 로 구현할 수 있습니다 .

곱셈 ( M)은 단순히 더하기 분포입니다. 두 세트 AB가 주어지면 위에서 설명한 것처럼 모든 세트의 합 { A + b | bB } (여기서 A + b 는 집합 { a + b | aA })입니다.

정수 비교는 내림차순으로 정렬 된 두 세트의 사전 비교가됩니다.

D두 세트 AB 를 나누기 위해 빈 세트를 몫으로 시작 하고 B + n이 A 보다 작거나 같은 최대 정수 n을 반복적으로 찾습니다 (이는 최대 값의 차이입니다) 의 및 B 아마도 마이너스 1), 추가 N 몫을 요소로하고 빼기 B + N에서 이와 같이 할 때까지, A는 이하된다 B , 즉, 그 나머지가 될 때까지한다.

물론 무료 점심은 없습니다. 우리는 십진수를 십진수로 변환하여 세금을 지불합니다. 실제로 10 진수로의 변환은 대부분의 런타임을 필요로합니다. 우리는 일반적인 산술 대신 위의 연산 만 사용하여 "일반적인 방법"으로 변환합니다.


호기심에서 벗어나는 것 : s=`sum(2**i for i in d)`+s변환 중에 내장 임의 정밀도 연산을 사용 하지 않습니까?
생성자

1
@TheConstructor No. d는 10 진수 한 자릿수이므로 i0에서 3 사이이며 전체 합은 0에서 9 사이입니다.
Ell

4

자바 8, 485 바이트

기능을 명명 다른 5 바이트로 줄일 수있는 d대신에 divide또는 다른 16 바이트 클래스 정의를 계산하지 경우.

public class G{int l(String a){return a.length();}String s(String n,String m){while(l(n)>l(m))m=0+m;String a="";for(int c=1,i=l(n);i>0;c=c/10){c=n.charAt(--i)+c-m.charAt(i)+9;a=c%10+a;}return e(a);}String e(String a){return a.replaceAll("^0+(?=[0-9])","");}String divide(String n,String m){String q="",p=q,y;for(int b=0,i=0;b<=l(n);i--){y=n.substring(0,b);if(l(y)==l(p)&&p.compareTo(y)<=0||l(y)>l(p)){y=s(y,p);n=y+n.substring(b);q+=i;b=l(y)+1;i=10;p=m+0;}p=s(p,m);}return e(q)+","+n;}}

다음과 같이 사용할 수 있습니다 :

public static void main(String[] args) {
    G devision = new G();
    System.out.println(devision.divide("20397882081197443358640281739902897356800000000",
            "265252859812191058636308480000000"));
    System.out.println(devision.divide("31035053229546199656252032972759319953190362094566672920420940313",
            "1234567891011121314151617181920"));
    System.out.println(devision.divide(
            "271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000",
            "247"));
}

굽힐 수 있는

76899763100160,0
25138393324103249083146424239449429,62459510197626865203087816633
1100573825740813795225181252819477770473619155158611722708681386445423816849801159141424129060075102231232666057768175183676764503262931271346408394876267875141461722640873365274628650676808557279259873162169126398101692109801549256156915750794061370041981513180387019893765753438422927286098434193260562682052606153857091520795991080960000000000000000000000000000000000000000000000000,0

언 골프 드 :

public class ArbitraryPrecisionDivision {

    /**
     * Length of String
     */
    int l(String a) {
        return a.length();
    }

    /**
     * substract m of n; n >= m
     */
    String s(String n, String m) {
        while (l(n) > l(m))
            m = 0 + m;
        String a = "";
        for (int c = 1, i = l(n); i > 0; c = c / 10) {
            c = n.charAt(--i) + c - m.charAt(i) + 9;
            a = c % 10 + a;
        }
        return e(a);
    }

    /**
     * trim all leading 0s
     */
    String e(String a) {
        return a.replaceAll("^0+(?=[0-9])", "");
    }

    /**
     * divide n by m returning n/m,n%m; m may not start with a 0!
     */
    String divide(String n, String m) {
        // q stores the quotient, p stores m*i, y are the b leading digits of n
        String q = "", p = q, y;
        for (int b = 0, i = 0; b <= l(n); i--) {
            y = n.substring(0, b);
            if (l(y) == l(p) && p.compareTo(y) <= 0 || l(y) > l(p)) {
                y = s(y, p);
                n = y + n.substring(b);
                q += i;
                b = l(y) + 1;
                i = 10;
                p = m + 0;
            }
            p = s(p, m);
        }
        return e(q) + "," + n;
    }

    public static void main(String[] args) {
        ArbitraryPrecisionDivision division = new ArbitraryPrecisionDivision();
        System.out.println(division.divide("20397882081197443358640281739902897356800000000",
                "265252859812191058636308480000000"));
        System.out.println(division.divide("31035053229546199656252032972759319953190362094566672920420940313",
                "1234567891011121314151617181920"));
        System.out.println(division.divide(
                "271841734957981007420619769446411009306983931324177095509044302452019682761900886307931759877838550251114468516268739270368160832305944024022562873534438165159941045492295721222833276717171713647977188671055774220331117951120982666270758190446133158400369433755555593913760141099290463039666313245735358982466993720002701605636609796997120000000000000000000000000000000000000000000000000",
                "247"));
    }
}

m1에서 9까지의 시간 으로 배열을 미리 계산하지 b=0않고 대신에 시작 하여 약간의 속도를 희생 b=l(m)했지만 많은 바이트를 절약했습니다. 임의 정밀도 추가에 관심이있는 경우 이전 버전을 참조하십시오 .

나는 이것이 가장 짧은 해결책이 아니라고 생각하지만 아마도 좋은 시작일 것입니다.


이것에 더하기, 곱하기 및 빼기를 구현하면 이것에 500 회 현상금을 지급합니다. : DI는 Stringy precision의 아이디어를 좋아합니다.
애디슨 크럼

@VoteToClose는이 내일을 보게 될 것입니다. 가장 어려운 부분이 완료된 것 같아요.
생성자

1

수학, 251 바이트

r=Reverse;f=FoldPairList;s={0}~Join~#&;
p[a_,b_]:={First@#,#[[2,1,-1,2]]}/.{Longest[0..],x__}:>{x}&@Reap@f[Sow@{Length@#-1,Last@#}&@NestWhileList[r@f[{#~Mod~10,⌊#/10⌋}&[#+Subtract@@#2]&,0,r@Thread@{#,s@b}]&,Rest@#~Join~{#2},Order[#,s@b]<=0&]&,0s@b,s@a]

설명

십진수에 대한 산술은에 의해 쉽게 구현 될 수 있습니다 FoldPairList. 예를 들어

times[lint_,m_]:=Reverse@FoldPairList[{#~Mod~10,⌊#/10⌋}&[m #2+#]&,0,Reverse@lint]

손으로 곱셈을하는 과정을 흉내냅니다.

times[{1,2,3,4,5},8]
(* {9,8,7,6,0} *)

테스트 사례

p[{1,2,3,4,5,6,7,8,9},{5,4,3,2,1}] 
(* {{2,2,7,2},{3,9,4,7,7}} *)

의미 123456789 / 54321= 2272...39477합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.