จำนวนจุดลอยตัวโดยประมาณที่มีความแม่นยำ n หลัก


9

เรามีจำนวนจุดลอยrระหว่าง 0 และ 1, pและจำนวนเต็ม

ค้นหาเศษส่วนของจำนวนเต็มด้วยตัวหารที่เล็กที่สุดซึ่งใกล้เคียงrกับpความแม่นยำอย่างน้อย-digit

  • อินพุต: r(หมายเลขจุดลอยตัว) และp(จำนวนเต็ม)
  • ผลลัพธ์: aและbจำนวนเต็มโดยที่
    • a/b(ลอย) ประมาณrจนกระทั่งpตัวเลข
    • b เป็นไปได้ที่น้อยที่สุดเช่นจำนวนเต็มบวก

ตัวอย่างเช่น:

  • ถ้าr=0.14159265358979และp=9,
  • แล้วผลที่ได้คือa=4687และb=33102,
  • 4687/33102=0.1415926530119026เพราะ

การแก้ปัญหาใด ๆ จะต้องทำงานในทางทฤษฎีด้วยความแม่นยำโดยพลการ

แม่นยำหมายถึงจำนวนของตัวเลขหลังจากที่ " 0." rใน ดังนั้นหากr=0.0123และp=3แล้วควรเริ่มต้นด้วยa/b 0.012หากpตัวเลขแรกของส่วนที่เป็นเศษส่วนของr0 เป็นพฤติกรรมที่ไม่ได้กำหนดเป็นที่ยอมรับ

เกณฑ์การชนะ:

  • อัลกอริทึมเร็วที่สุดชนะ ความเร็วถูกวัดใน O (p)
  • หากมีอัลกอริธึมที่เร็วที่สุดหลายตัว
  • คำตอบของฉันถูกแยกออกจากกลุ่มผู้ชนะที่เป็นไปได้

ps คณิตศาสตร์ส่วนที่เป็นจริงได้ง่ายขึ้นมากเป็นดูเหมือนว่าฉันขอแนะนำให้อ่านนี้โพสต์

คำตอบ:


7

JavaScript, O (10 p ) & 72 ไบต์

r=>p=>{for(a=0,b=1,t=10**p;(a/b*t|0)-(r*t|0);a/b<r?a++:b++);return[a,b]}

มันเป็นเรื่องเล็กน้อยที่จะพิสูจน์ว่าวนซ้ำจะทำหลังจากมากที่สุด (10 p ) ซ้ำ

ขอบคุณมากสำหรับแนวคิดของ Neil บันทึก 50 ไบต์


ทำไมคุณเล่นซอด้วยpadEndและmatch? คุณไม่สามารถsliceแยกความยาวให้ถูกต้องแล้วลบออกได้ไหม
Neil

@ Neil ขออภัยฉันไม่เข้าใจประเด็นของคุณ เพิ่มpadEndใช้สำหรับ testcase และf(0.001,2) f(0.3,2)
tsh

ผมคิดว่าคุณสามารถลดความซับซ้อนลงไปบางสิ่งบางอย่างตามสายของ(r,p)=>{for(a=0,b=1;`${a/b}`.slice(0,p+2)-`${r}`.slice(0,p+2);a/b<r?a++:b++);return[a,b]}(ไม่แข็งแรงเล่นกอล์ฟอย่างเต็มที่)
Neil

@Neil 120 -> 70 ไบต์ :)
tsh

โอ้โหดีกว่ามาก!
Neil

4

Haskell , O (10 p ) ในกรณีที่เลวร้ายที่สุด121 119 ไบต์

g(0,1,1,1)
g(a,b,c,d)r p|z<-floor.(*10^p),u<-a+c,v<-b+d=last$g(last$(u,v,c,d):[(a,b,u,v)|r<u/v])r p:[(u,v)|z r==z(u/v)]

ลองออนไลน์!

บันทึก 2 ไบต์ขอบคุณ Laikoni

ผมใช้อัลกอริทึมจาก/math/2432123/how-to-find-the-fraction-of-integers-with-the-smallest-denominator-matching-an-i

ในแต่ละขั้นตอนช่วงเวลาใหม่คือครึ่งหนึ่งของช่วงเวลาก่อนหน้า ดังนั้นขนาดช่วงเวลาคือ2**-nที่ซึ่งnเป็นขั้นตอนปัจจุบัน เมื่อ2**-n < 10**-pใดเราแน่ใจว่ามีการประมาณที่ถูกต้อง แต่ถ้าแล้วn > 4*p สรุปก็คือว่าอัลกอริทึม2**-n < 2**-(4*p) == 16**-p < 10**-pO(p)

แก้ไขตามที่ระบุโดย orlp ในความคิดเห็นการอ้างสิทธิ์ข้างต้นเป็นเท็จ ในกรณีที่เลวร้ายที่สุดr = 1/10**p( r= 1-1/10**pเป็นที่คล้ายกัน) จะมีขั้นตอน10**p 1/2, 1/3, 1/4, ...มีวิธีแก้ปัญหาที่ดีกว่า แต่ฉันไม่มีเวลาที่จะแก้ไข


ฉันรู้ว่ากอล์ฟรหัสเป็นเพียงเป้าหมายรอง แต่คุณสามารถวางและบันทึกไบต์ที่สองด้วยf= z<-floor.(*10^p),u<-a+c,v<-b+d
Laikoni

@Laikoni ฉันไม่ได้นับสองไบต์ ฉันไม่ทราบวิธีลบf=ใน TIO ในรหัส Haskell
jferard

คุณสามารถเพิ่ม-cppธงคอมไพเลอร์และเขียนf=\ ในส่วนหัว: ลองออนไลน์!
Laikoni

"ในแต่ละขั้นตอนช่วงใหม่จะเป็นครึ่งหนึ่งของช่วงก่อนหน้านี้" คุณรู้เรื่องนี้ได้อย่างไร? ขั้นตอนแรกคือ 1/2, ใช่ แต่จากนั้นขั้นตอนต่อไปคือตัวอย่างค่ามัธยฐานของ 1/2 และ 1/1 ที่ให้ 2/3 ซึ่งไม่ลดลงครึ่งหนึ่ง
orlp

@ orlp คุณไม่ต้องสงสัยเลย ฉันมองโลกในแง่ดีเกินไปและความซับซ้อนคือ O (10 ^ p) ในกรณีที่เลวร้ายที่สุด ฉันมีวิธีแก้ปัญหาที่ดีกว่า แต่ไม่มีเวลาเขียนได้เลย
jferard

0

C, 473 ไบต์ (ไม่มีบริบท), O (p), ไม่มีการแข่งขัน

วิธีการแก้ปัญหานี้ใช้ส่วนคณิตศาสตร์ที่มีรายละเอียดในการโพสต์ที่ยอดเยี่ยมนี้ ฉันคำนวณcalc()เป็นขนาดคำตอบเท่านั้น

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void calc(float r, int p, int *A, int *B) {
  int a=0, b=1, c=1, d=1, e, f;
  int tmp = r*pow(10, p);
  float ivl = (float)(tmp) / pow(10, p);
  float ivh = (float)(tmp + 1) / pow(10, p);

  for (;;) {
    e = a + c;
    f = b + d;

    if ((ivl <= (float)e/f) && ((float)e/f <= ivh)) {
      *A = e;
      *B = f;
      return;
    }

    if ((float)e/f < ivl) {
      a = e;
      b = f;
      continue;
    } else {
      c = e;
      d = f;
      continue;
    }
  }
}

int main(int argc, char **argv) {
  float r = atof(argv[1]);
  int p = atoi(argv[2]), a, b;
  calc(r, p, &a, &b);
  printf ("a=%i b=%i\n", a, b);
  return 0;
}

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