Ondalık gösterim dönemi


16

Tek bir pozitif tam sayı n alan ve 1 / n ondalık gösterim dönemini döndüren bir fonksiyon yazın .

Test senaryoları:

1 -> 1               # 1/1 = 1.0000...... = 1._0
2 -> 1               # 1/2 = 0.5000...... = 0.5_0
3 -> 1               # 1/3 = 0.3333...... = 0._3
7 -> 6               # 1/7 = 0.14285714.. = 0._142857
13 -> 6
14 -> 6
123 -> 5
345 -> 22
654 -> 108
12345 -> 822
67890 -> 120

Bu . Dönemi doğrudan döndüren yerleşik yapılara veya kitaplıklara izin verilmez. En az 100000'e kadar olan sayılar makul bir süre içinde çalışmalıdır (en fazla birkaç dakika).


Soru, "en az 100000'e kadar olan rakamların makul bir süre içinde çalışması gerektiğini" belirtiyor, ancak program bundan daha büyük sayılar için doğru cevabı vermek zorunda mı? Yoksa sadece 100000'e kadar doğru bir algoritma kullanmak kabul edilebilir mi?
FireFly

1
@FireFly Algoritmaları doğru yanıtı sağlamalıdır.
Howard

2
1 neden 1 döndürür? 0 mı düşünürdüm?
Timtech

Timtech1.00000000000000000000000000000000000
Cruncher

@Cruncher Oh teşekkürler, şimdi anladım.
Timtech

Yanıtlar:


11

APL, 19 karakter / bayt *

{(↑⍳⍨1∘↓)⌽⍵|10x*⍳⍵}

Nars2000 . Önceki sürüm bazı numaralarda yanlıştı, bu doğru olmalı. 50'ye kadar olan tüm sayıları elle kontrol ettim.

Yine, döneme bakma fikri için Ben Reich'e kredi gidiyor10^i (mod x)

Parçalarına ayrıştırılmış görünüm

{                     ⍳⍵}   generate all naturals up to the argument ⍵
                 10x*       raise 10 to each of them, with unlimited precision
              ⍵|            compute the respective remainders mod ⍵
            ⌽               reverse the list
 (  ⍳⍨    )                 (fork) find the position of the first occurrence
  ↑                         of the fist element of the list
       1∘↓                  in the remainder of the list

Örnekler

      {(↑⍳⍨1∘↓)⌽⍵|10x*⍳⍵}¨1 2 3 7 13 14 123 345 654 12345 67890
1 1 1 6 6 6 5 22 108 822 120

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ *: APL, APL sembollerini üst 128 bayt değerleriyle eşleştiren kendi (eski) tek baytlık karakter kümesiyle
yazılabilir. Bu nedenle, puanlama amacıyla, yalnızca ASCII karakterleri ve APL sembolleri kullanan bir N karakterleri programı N bayt uzunluğunda kabul edilebilir.


Giriş için doğru cevabı alamıyorum 20. Lütfen doğrulayabilir misiniz?
Howard

Gönderdiğiniz örnekleri takip ettim. Örneğinizde, 1/2 = 0.5 -> 1, doğal olarak 1/20 = 0.05 -> 2. Ne alıyorsunuz?
Tobia

Doğru cevap 1 olacaktır, çünkü 1/20 = 0,05_0_.
Howard

Anlıyorum. Bana biraz ver, cevabımı gözden geçireceğim.
Tobia

4yanlış cevap verecek gibi görünüyor, çünkü 10 != 100 (mod 4).
Peter Taylor

7

GolfScript ( 42 27)

{:x)1\[{.10*x%}*]-1%(?)}:P;

Karşılaştırma süresi: 5 sn. Karşılaştırma kodu:

'"The time is #{Time.now#1
}"'~ puts
[1 2 3 7 13 14 123 345 654 12345 67890 99991]{[P]p}%
'"The time is #{Time.now#2
}"'~ puts

Dönemine bakmanın temel fikri için Ben Reich'e teşekkür ederiz 10^i (mod x).

açıklama

Bu süre p, yeterince büyük olan herkes için isahip olduğumuz en küçük pozitif tamsayı olarak tanımlanır frac(10^i * 1/x) = frac(10^(i+p) * 1/x). Bunu biraz basitleştirebiliriz frac(10^i / x) = frac(10^(i+p) / x). Şimdi, frac(a / x) = frac(b / x)IFF a == b (mod x), biz böyle tüm yeterince büyük için en küçük pozitif tam sayı arıyorsanız bu yüzden i: 10^i == 10^(i+p) (mod x).

Farz edin 10^i == 10^(i+p) (mod x). Sonra 10^(i+1) == 10 * 10^i == 10 * 10^(i+p) == 10^(i+p+1) (mod x); bir kez tekrar edersek, kırılmaz bir döngü içerisindeyiz.

Sadece xfarklı değerler vardır (mod x), bu yüzden güvercin deliği prensibi ile ilk x + 1değerlerinde bir tekrar almalıyız 10^i (mod x).

Yukarıdaki kodun yaptığı şey * x + 2değerlerini hesaplamaktır 10^i (mod x). Sonra sonuncusunun bir tekrar olması garanti edilir ve listeyi tersine çevirip arayarak en son olayı bulabilirim. Üstelik, sadece tek bir arama yaptığım için bu sahte zaman.

* Ekstra, özel durumu ele almaktır x = 1, çünkü azaltmıyorum 10^0 (mod x)ve bu yüzden bir 0giriş arıyorum [1].


Müthiş! Daha iyi bir çözümden beri cevabımı sildim! -
Ben Reich

7

Golfscript - 26 bayt

{:i.)+.,{;10*i%.}%i>|,}:f;

Düzenle: 1ondalık gösterimin uzunluğu yerine ondalık sona ererse çıktı olarak güncellenir .

Oldukça verimli bir versiyon. 67890 değeri yaklaşık 10 saniye ve 99991 yaklaşık 20 saniye içinde çalışır. Öncekinden biraz daha yavaş (kabaca yarısı kadar hızlı), çünkü yinelenen aralık iki katına çıktı, ilk yarısı yok sayıldı.

Alternatif, ayrıca 26 bayt

{:i.)+.n*{*i%.}%i>)^^,}:f;

Dize üzerinde yineleme ile gerçekleştirilen bu bir eser "\n"*(2*i+1), nerede iişleve geçirilen değerdir. Her seferinde bloğa iletilen değer, sıra değeri "\n"olan 10'dur .

)^^Bir iş çevresinde bir parçasıdır. Bir dizeden bir karakteri çözdüğünüzde , sonuç yukarıda belirtildiği gibi kaldırılan karakterin sıralı değeridir. Bununla birlikte, bu değerin tekrar eklenmesi , karakterden ziyade bu sayının dize temsilini ekleyecektir - oldukça simetrik olmayan davranış ve bence bir tasarım hatası. Bunu gerçekten yapmak istediyseniz, önce dizgi yapmak yalnızca bir bayta mal olur.

Nihai değerin fazladan bir kopyası zaten yığın üzerindedir, bu yüzden ilk değeri yeniden )ekler veya kaldırır, böylece ilk değeri yeniden ekler veya kaldırır. int op stringDize temsilinden ziyade bir karakter olarak ele alınırsa , onun )^^yerini alabilir |.

Dizelerin (Golfscript'te bir dizi girişi olarak saklandığı) her karakter modunun 256 değerini görüntülerken, her karakterin değerlerinin kendisinin bu aralığın dışında olabileceğini unutmayın. Teklik (ayarlanmış işlemler aracılığıyla) veya içerme (aracılığıyla ?) için test edilirken , görüntüleme değeri yerine karşılaştırılan gerçek değerdir.

Geçerli Golfscript yorumlayıcısı için bir yama dosyası :

61c61
<       to_gs
---
>       Gstring.new([self])

Yukarıda anlatılanlar sadece davranışını etkileyecektir string op int(tam tersi ve yardımcısı), opbiri
+-|&^. Davranışı da dahil olmak üzere her şey etkilenmez Gint`.

Aşağıdaki 24 baytlık çözüm geçerli olur:

{:i.)+.n*{*i%.}%i>|,}:f;

Ve bu aynı zamanda birçok başka çirkin çözümü de düzeltir .


Python - 48 bayt

f=lambda n:len(set(10**-~i%n for i in range(n)))

En verimli çözüm değil, ancak 100000'den küçük değerler için makul .

FWIW, temel eleman Ondalık döngüsel sayılar üretme çözümümle aynı .

Aynı kodun daha verimli bir sürümü ( 70 bayt ):

 def f(n):
  a=[];i=10%n
  while i not in a:a+=i,;i=i*10%n
  return len(a)

99991 değeri bir saniyeden az sürer.


@PeterTaylor ordiziyi boş bir dizgiye ekler . Bu ayarlı bir işlem olduğundan, tüm kopyalar önceden kaldırılır.
primo

Ancak boş dize nereden geliyor? Eğer fonksiyon kendi kendine yetecekse, ekstra bir bayt harcamak ve bunu yapmak zorunda kalacağınızı düşünüyorum .|.
Peter Taylor

1
@PeterTaylor düzeltildi .
primo

1
Davranışını değiştirmek birçok programı string int +kırar . Bu tip çiftte diğer op'ların ne sıklıkta kullanıldığından emin değilim.
Peter Taylor

@PeterTaylor Kabul ediyorum, olur. Ancak düşünün: int'i char: []+''+vs'ye dönüştürün ''+. Dizeye char olarak ekleme int,: []++vs +. Dize temsili olarak int öğesini dize: +vs olarak ekleyin `+. Mevcut uygulamada, int''+eşanlamlıdır int`, bu dizi için zorlama ve sonra ascii char istiyorsanız bir dizeye zorlama düşüncesizlik dikkate alınarak savurgan görünüyor.
primo

3

GolfScript, 48 47 46

@PeterTaylor'a iki karakter ayırdığı için teşekkürler.

{2{1$1$%!{.@\/\d}*}:d~;5d;9{2$%}{10*9+}/+,}:f;

J'yi kullanmayı denedim, ama bana her türlü garip sonuç vermeye devam etti.

Çevrimiçi test edin

Bu temel olarak 2 ve 5'i sayıdan ayırır (2 ve 5, 10'un ana faktörleridir ve karşılıklılıkları sonlanır ve algoritmayı doldurur), sonuçta elde edilen sayı 10 ^ n - 1'i ayıracak şekilde en düşük n tamsayı periyot.


3
Fonksiyonunuza ilk çağrı hangisinin olacağını biliyorsanız, tanımı orada satır içine alabilirsiniz. Yani {...}:d;...dsenin yerine 1 karakter kurtar...{...}:d~
Peter Taylor

@PeterTaylor teşekkürler, bunu düşünmemiştim
Volatility

1
Ben'e fyığından ayrılmama hakkında yorum yaptıktan sonra , bunu da yaptığınızı fark ettim. Gerçekten ;diğer dillerle adil karşılaştırma için bir işlev pop eklemek gerekir .
Peter Taylor

2
Başka bir mikro optimizasyon: int array ,)\;kısaltılabilir int array +,.
Peter Taylor

2

Perl, 52 karakter

sub f{($p,%r)=1;1until$r{$p=$p*10%$_[0]}++;~~keys%r}

Bu, doğrudan yaklaşımın karmaşık olmayan bir uygulamasıdır. (Neyse ki doğrudan yaklaşım da oldukça etkilidir: modulo aritmetiği sayesinde, matematik asla giriş değerinin 10 katından fazla bir sayı ile uğraşmak zorunda kalmaz.)

Zorluk bir işlev belirttiğinden, tam bir program için uğraşmayacağım bir şey olan değişkenlerimi (yeniden) başlatmaya zorlandığımı hissettim. Benzer şekilde, ~~fonksiyonun skaler bir bağlamda çağrılacağından emin olabiliyorsa, son ifadede gereksizdir.


20Yanlış sonuç verdiği girişleri deneyin .
Howard

2

Clojure, 102, 117, 115, 106

biçimlendirilmemiş:

(defn r([n](r{}(iterate #(mod(* % 10)n)10)0))([a[f & s]i](if(a f)(- i(a f))(recur(assoc a f i)s(inc i)))))

biçimlendirilmiş:

(defn r
  ([n] (r {} (iterate #(mod (* % 10) n) 10) 0))
  ([a [f & s] i]
    (if (a f)
      (- i (a f))
      (recur
        (assoc a f i)
        s
        (inc i)))))

Çalışma süresi döneme göre artar. Bilgisayarımdaki örnek değerler için neredeyse anında.

Temel olarak, bu uzun bölümdeki her adımdan sonra çıkarma sonucunu hesaplar. Herhangi bir noktada, bu sayı kendisinden önce hesaplanmış olanla aynı ise bir döngü algılanır.


Kod girişle kesiliyor 20. Lütfen doğrulayabilir misiniz?
Howard

Haklısın, yukarıdaki çözüm hatalı. Tamir edip edemeyeceğimi göreceğim.
RedDeckWins

20 için beklenen çıktı nedir?
RedDeckWins

Doğru cevap 1 olur.
Howard

Örneğin 12 ile 20 için, ilk algoritma, girdilerin çok sayıda başarısız olur gitmek için iyi olmalı
girişte RedDeckWins

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.