ปัดเศษสตริง


10

ตัวเลขทศนิยมบางตัวไม่สามารถแสดงอย่างแม่นยำว่าเป็นเลขฐานสองแบบลอยตัวเนื่องจากเป็นตัวแทนภายในของเลขฐานสองแบบลอยตัว ตัวอย่างเช่น: การปัดเศษ 14.225 ถึงสองหลักทศนิยมไม่ได้ส่งผลให้เกิด 14.23 เนื่องจากอาจมีหนึ่งใน 14.22

งูหลาม :

In: round(14.225, 2)
Out: 14.22

อย่างไรก็ตามสมมติว่าเรามีการแทนค่าสตริงของ 14.225 เป็น '14 .225 'เราควรจะสามารถบรรลุการปัดเศษ '14 .23' ที่ต้องการในการแทนค่าสตริงได้

วิธีการนี้สามารถกำหนดให้เป็นความแม่นยำโดยพลการ

Python 2/3 วิธีแก้ปัญหาที่เป็นไปได้

import sys

def round_string(string, precision):
    assert(int(precision) >= 0)
    float(string)

    decimal_point = string.find('.')
    if decimal_point == -1:
        if precision == 0:
            return string
        return string + '.' + '0' * precision

    all_decimals = string[decimal_point+1:]
    nb_missing_decimals = precision - len(all_decimals)
    if nb_missing_decimals >= 0:
        if precision == 0:
            return string[:decimal_point]
        return string + '0' * nb_missing_decimals

    if int(all_decimals[precision]) < 5:
        if precision == 0:
            return string[:decimal_point]
        return string[:decimal_point+precision+1]

    sign = '-' if string[0] == '-' else '' 
    integer_part = abs(int(string[:decimal_point]))
    if precision == 0:
        return sign + str(integer_part + 1)
    decimals = str(int(all_decimals[:precision]) + 1)
    nb_missing_decimals = precision - len(decimals)
    if nb_missing_decimals >= 0:
        return sign + str(integer_part) + '.' + '0' * nb_missing_decimals + decimals
    return sign + str(integer_part + 1) + '.' + '0' * precision

ลองออนไลน์!

การใช้งาน :

     # No IEEE 754 format rounding
In:  round_string('14.225',2)
Out: '14.23'

     # Trailing zeros
In:  round_string('123.4',5)
Out: '123.40000'

In: round_string('99.9',0)
Out: '100'

    # Negative values
In: round_string('-99.9',0)
Out: '-100'

In: round_string('1',0)
Out: '1'

    # No unnecessary decimal point
In: round_string('1.',0)
Out: '1'

    # No unnecessary decimal point
In: round_string('1.0',0)
Out: '1'

In:  for i in range(8): 
         print(round_string('123456789.987654321',i))
Out: 123456790
     123456790.0
     123456789.99
     123456789.988
     123456789.9877
     123456789.98765
     123456789.987654
     123456789.9876543

งาน

อาร์กิวเมนต์อินพุต 1 : สตริงที่มี

  • อย่างน้อยหนึ่งหลัก ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  • อย่างน้อยหนึ่งจุดทศนิยม ( .) ซึ่งจะต้องนำหน้าด้วยตัวเลขอย่างน้อยหนึ่งหลัก
  • เครื่องหมายลบ ( -) เป็นอักขระตัวแรก

อาร์กิวเมนต์อินพุต 2 : จำนวนเต็มที่ไม่เป็นลบ

เอาท์พุท : สตริงกลม (ฐาน 10) อย่างถูกต้อง

การปัดเศษ = ปัดครึ่งห่างจากศูนย์

นี่คือรหัสกอล์ฟจำนวนไบต์ต่ำสุดชนะ!


@KevinCruijssen 1) คุณไม่จำเป็นต้องยึดติดกับสายอักขระในการใช้งานของคุณและได้รับอนุญาตให้ใช้การปัดเศษในตัว น่าเสียดายที่ (สำหรับคำถาม) มาตรฐาน IEEE 754 เป็นมาตรฐานที่ใช้กันอย่างแพร่หลายดังนั้นการปัดเศษในตัวจะไม่ส่งผลให้เกิดพฤติกรรมที่ต้องการ 2) โอเคไม่ทราบเกี่ยวกับกล่องทราย
แมทเทียส

TI-Basic: round(A,B5 bytes
Julian Lachniet

1
เกี่ยวกับอาร์กิวเมนต์อินพุตที่สอง: 0ไม่ใช่จำนวนเต็มบวกมันคือ "ไม่เป็นเชิงลบ"
Stewie Griffin

1
ฉันคิดว่าเราเพิ่มศูนย์ต่อท้ายหากจำเป็น? คุณสามารถเพิ่มกรณีทดสอบได้123.4 & 5 --> 123.40000หรือไม่? หรือเราสามารถสมมติว่าอินพุตที่สองจะไม่ใหญ่กว่าจำนวนทศนิยมหลังจากที่จุดในอินพุตแรก?
Kevin Cruijssen

1
@Matthias ยกเว้นว่าคุณสามารถรวม Python กับ JavaScript (ฉันไม่เคยตั้งโปรแกรม Python และ JS แทบจะไม่ดังนั้นฉันสุจริตไม่ทราบว่าเป็นไปได้) ไม่ แต่คุณสามารถเพิ่มลิงค์ทดลองใช้ออนไลน์พร้อมรหัสทดสอบได้ตลอดเวลา แก้ไข: นอกจากนี้โดยปกติแล้วจะดีกว่าที่จะรออย่างน้อยสองสามวันจนกว่าคุณจะยอมรับคำตอบ
Kevin Cruijssen

คำตอบ:


2

APL (Dyalog) 4 ไบต์

Dyalog APL ใช้ความแม่นยำภายในเพียงพอ

⎕⍕⍎⍞

ลองออนไลน์!

⍎⍞ ดำเนินการอินพุตสตริง

⎕⍕ รับอินพุตตัวเลขและใช้ความแม่นยำสำหรับการจัดรูปแบบ


ทำไม 4 นี้แทน 8 ไบต์?
แมทเธียสส์

@Matthias เนื่องจากDyalog APL มี SBCS
2017

5

Perl, 22 20 ไบต์

printf"%.*f",pop,pop

โดยใช้:

perl -e 'printf"%.*f",pop,pop' 123456789.987654321 3

มันเป็นรหัสของ Dada ก่อนหน้านี้:

printf"%*2\$.*f",@ARGV

2
printf"%.*f",pop,popควรทำงาน
Dada

5

PHP, 33 31 ไบต์

PHP รอบถูกต้องเช่นกัน (อย่างน้อยใน 64 บิต):

printf("%.$argv[2]f",$argv[1]);

รับอินพุตจากอาร์กิวเมนต์บรรทัดรับคำสั่ง -rทำงานด้วย

PHP, ไม่มีบิวด์อิน, 133 ไบต์

[,$n,$r]=$argv;if($p=strpos(_.$n,46))for($d=$n[$p+=$r],$n=substr($n,0,$p-!$r);$d>4;$n[$p]=(5+$d=$n[$p]-4)%10)$p-=$n[--$p]<"/";echo$n;

ทำงานด้วย-nrหรือทดสอบออนไลน์

ทำให้พังถล่ม

[,$n,$r]=$argv;             // import arguments
if($p=strpos(_.$n,46))      // if number contains dot
    for($d=$n[$p+=$r],          // 1. $d= ($r+1)-th decimal 
        $n=substr($n,0,$p-!$r); // 2. cut everything behind $r-th decimal
        $d>4;                   // 3. loop while previous decimal needs increment
        $n[$p]=(5+$d=$n[$p]-4)%10   // B. $d=current digit-4, increment current digit
    )
        $p-=$n[--$p]<"/";           // A. move cursor left, skip dot
echo$n;

ไบต์ว่างไม่ทำงาน substrดังนั้นผมจึงต้องใช้


1
คุณสามารถเขียน"%.$argv[2]f"แทนการ"%.{$argv[2]}f"บันทึก 2 ไบต์
Ismael Miguel

4

Ruby 2.3, 12 + 45 = 57

ใช้BigDecimalบิวด์อิน แต่จำเป็นต้องมีก่อนการใช้งานซึ่งมีราคาถูกกว่าเพื่อใช้เป็นแฟล็ก

ธง: -rbigdecimal

ฟังก์ชั่น:

->(s,i){BigDecimal.new(s).round(i).to_s('f')}

Ruby 2.3 โดยค่าเริ่มต้นใช้ ROUND_HALF_UP


4

Javascript (ES6), 44 ไบต์

n=>p=>(Math.round(n*10**p)/10**p).toFixed(p)

ลองออนไลน์:

const f = n=>p=>(Math.round(n*10**p)/10**p).toFixed(p)

console.log(f('14.225')(2));

[...Array(8).keys()].map(i=>console.log(f('123456789.987654321')(i)))

console.log(f('123.4')(5))


4

Python, 114 105 103 96 91 89 ไบต์

บันทึก 5 ไบต์ขอบคุณKevin Cruijssen
บันทึก 2 ไบต์ขอบคุณKrazor

from decimal import*
d=Decimal
lambda x,y:d(x).quantize(d('0.'[y>0]+'1'*y),ROUND_HALF_UP)

ลองออนไลน์!


1
from decimal import *และการลบทั้งสามd.นั้นสั้นกว่า 4 ไบต์
Kevin Cruijssen

@KevinCruijssen: ขอบคุณ!
Emigna

2
คุณสามารถทำได้d=Decimalและd() ซึ่งจะประหยัดอีก 5 (อาจจะผิดง่วงนอนมาก)
FMaz

@ Krazor: เว้นแต่ฉันทำผิดมันช่วยฉัน 2 ไบต์ ขอบคุณ!
Emigna

ว้าวนั่นคือสิ่งที่ฉันตั้งใจ จะทำให้ความคิดง่วงนอนของฉันยังไงต่อไป
FMaz

4

REXX 24 ไบต์

arg n p
say format(n,,p)

เนื่องจาก REXX ใช้การแสดงข้อความเป็นตัวเลขเสมอการปัดเศษตัวเลขที่ถูกต้องนั้นฟรี

ลองออนไลน์!


ว้าว. การใช้ภาษาในทางที่ผิด
Matthew Roh

REXX มีคอมไพเลอร์ออนไลน์หรือไม่?
Kevin Cruijssen

เป็นภาษาที่ตีความ (ส่วนใหญ่)
idrougge


3

BASH, 26 23 21 ไบต์

bc<<<"scale=$2;$1/1"

การใช้

บันทึกไปที่ round_string.sh, chmod + x round_string.sh

./round_string.sh 23456789.987654321 3

แก้ไข: ไม่จำเป็นต้องโหลดห้องสมุด


คำอธิบาย: bc ใช้ precission โดยพลการสร้าง doc ที่นี่พร้อมกับ '<<<' ที่มีค่าของสเกลเป็นพารามิเตอร์ที่สองและพารามิเตอร์แรกหารด้วย 1 เพื่อบังคับการตีความสเกล
marcosm 17'17

2
สิ่งนี้ให้14.22การป้อนข้อมูล14.225 2ไม่ใช่14.23
Digital Trauma

3

AHK, 25 ไบต์

a=%1%
Send % Round(a,%2%)

อีกครั้งฉันถูกสกัดกั้นโดยการไร้ความสามารถของ AHK เพื่อใช้ผ่านในพารามิเตอร์โดยตรงในฟังก์ชั่นที่ยอมรับทั้งชื่อตัวแปรหรือตัวเลข ถ้าฉันแทนที่aด้วย1ในฟังก์ชั่นจะใช้ค่าRound 1หากฉันลอง%1%ก็จะพยายามใช้เนื้อหาแรกของอาร์กิวเมนต์เป็นชื่อตัวแปรซึ่งใช้ไม่ได้ ต้องตั้งเป็นตัวแปรอื่นเสียค่าใช้จ่ายครั้งแรกฉัน 6 ไบต์


3

แบตช์ 390 ไบต์

@echo off
set s=%1
set m=
if %s:~,1%==- set m=-&set s=%s:~1%
set d=%s:*.=%
if %d%==%s% (set d=)else call set s=%%s:.%d%=%%
for /l %%i in (0,1,%2)do call set d=%%d%%0
call set/ac=%%d:~%2,1%%/5
call set d=00%s%%%d:~,%2%%
set z=
:l
set/ac+=%d:~-1%
set d=%d:~,-1%
if %c%==10 set c=1&set z=%z%0&goto l
set d=%m%%d:~2%%c%%z%
if %2==0 (echo %d%)else call echo %%d:~,-%2%%.%%d:~-%2%%

คำอธิบาย เริ่มต้นด้วยการแยกเครื่องหมายหากมี จากนั้นแบ่งตัวเลขเป็นตัวเลขจำนวนเต็มและเศษส่วน เศษส่วนจะเต็มด้วยn+1ศูนย์เพื่อให้แน่ใจว่ามีมากกว่าnตัวเลขตัวเลขหลักที่n(เป็นดัชนีศูนย์) ถูกหารด้วย 5 และนี่คือการเริ่มต้น ตัวเลขจำนวนเต็มและnเศษส่วนจะถูกต่อกันและตัวละครที่นำติดตัวเพิ่มตามตัวอักษร (ศูนย์ป้องกันพิเศษสำหรับระลอกการกระเพื่อม) หลังจากการหยุดการกระเพื่อมระลอกหมายเลขจะถูกสร้างขึ้นใหม่และใส่จุดทศนิยมใด ๆ


3

TI-Basic, 53 16 ไบต์

TI-Basic ไม่ใช้ IEEE และวิธีการด้านล่างใช้ได้กับตำแหน่งทศนิยม 0-9 (รวม)

Prompt Str1,N
toString(round(expr(Str1),N

ขอบคุณ @JulianLachniet ที่แสดงว่า CE calcs มี toString(คำสั่งที่ฉันไม่ทราบ (ต้องใช้ Color Edition calcs OS 5.2 หรือสูงกว่า)

ป.ล. ฉันมีบรรทัดที่สองด้วยsub(Str1,1,N+inString(Str1,".แต่แล้วฉันก็รู้ว่ามันไร้ประโยชน์


วิธีการNใช้งานอย่างไร
Matthias

@ Matias ขอบคุณที่จับสะกดผิด! ฉันลบสามไบต์สุดท้ายด้วยการแก้ไขก่อนหน้านี้โดยไม่ตั้งใจ
Timtech

3

Java 7, 77 72 71 ไบต์

<T>T c(T n,int d){return(T)"".format("%."+d+"f",new Double(n+""));}

-1 ไบต์ขอบคุณ@cliffroot

คำตอบ 72 ไบต์:

String c(String n,int d){return n.format("%."+d+"f",new Double(n));}

Java แตกต่างจาก Python รอบแล้วอย่างถูกต้องและส่งกลับสตริงเมื่อคุณใช้String.format("%.2f", aDouble)กับ2แทนที่ด้วยปริมาณของทศนิยมที่คุณต้องการ

แก้ไข / หมายเหตุ: ใช่ฉันรู้new Float(n)คือ 1 ไบต์สั้นกว่าแต่เห็นได้ชัดว่ามันล้มเหลวสำหรับกรณีทดสอบด้วยnew Double(n) ดูรหัสทดสอบนี้เกี่ยวกับ Double vs Float123456789.987654321

คำอธิบาย:

<T> T c(T n, int d){               // Method with generic-T & integer parameters and generic-T return-type (generic-T will be String in this case)
  return (T)"".format("%."+d+"f",  //  Return the correctly rounded output as String
    new Double(n+""));             //  After we've converted the input String to a decimal
}                                  // End of method

รหัสทดสอบ:

ลองที่นี่

class M{
  static <T>T c(T n,int d){return(T)"".format("%."+d+"f",new Double(n+""));}

  public static void main(String[] a){
    System.out.println(c("14.225", 2));
    System.out.println(c("123.4", 5));
    System.out.println(c("99.9", 0));
    System.out.println(c("-99.9", 0));
    System.out.println(c("1", 0));
    System.out.println(c("1.", 0));
    System.out.println(c("1.0", 0));
    for(int i = 0; i < 8; i++){
      System.out.println(c("123456789.987654321", i));
    }
  }
}

เอาท์พุท:

14.23
123.40000
100
-100
1
1
1
123456790
123456790.0
123456789.99
123456789.988
123456789.9877
123456789.98765
123456789.987654
123456789.9876543

1
สั้นลงหนึ่งไบต์:<T>T c(T n,int d){return(T)"".format("%."+d+"f",new Double(n+""));}
หน้าผา

2
การแก้ปัญหานี้ไม่ได้ทำงาน แม้ว่าตัวอย่างอาจจะเป็นปัญหาแบบ half-even / away-0 แต่จะมีข้อผิดพลาดของ floating point เกิดขึ้นและ OP ได้ชี้แจงว่าควรสนับสนุนความแม่นยำโดยพลการ
CAD97

1
ในความเป็นจริงคุณล้มเหลวในกรณีตัวอย่างในคำถามที่คุณทำซ้ำที่นี่: 123456789.987654321, 4ควรจะเป็น123456789.9877ไม่ได้123456789.9876
CAD97

2

Python (2/3), 394 ไบต์

def rnd(s,p):
    m=s[0]=='-'and'-'or''
    if m:s=s[1:]
    d=s.find('.')
    l=len(s)
    if d<0:
        if p>0:d=l;l+=1;s+='.'
        else:return m+s
    e=(d+p+1)-l
    if e>0:return m+s+'0'*e
    o=''
    c=0
    for i in range(l-1,-1,-1):
        x=s[i]
        if i<=d+p:
            if i!=d:
                n=int(x)+c
                if n>9:n=0;c=1 
                else:c=0
                o+=str(n)
            else:
                if p>0:o+=x
        if i==d+p+1:c=int(x)>4
    if c:o+='1'
    return m+''.join(reversed(o))

ใช้งานได้กับตัวเลขที่มีความแม่นยำตามอำเภอใจ


5
เฮ้และยินดีต้อนรับสู่ PPCG! อย่างไรก็ตามนี่ไม่ใช่กอล์ฟ มีเป็นจำนวนมากของช่องว่างที่คุณสามารถลบ คำตอบในเว็บไซต์นี้จำเป็นต้องได้รับการตีกอล์ฟขออภัย
Rɪᴋᴇʀ

เพียงบางสิ่ง (มีโอกาสมากขึ้น) ... ชื่อฟังก์ชันสามารถเป็นหนึ่งไบต์ บรรทัดแรกสามารถใช้s[0]<'0'และยังสามารถใช้การคูณสตริงได้, m='-'*(s[0]<'0'). บรรทัดที่ไม่มีคำสั่งบล็อกใด ๆ สามารถรวมเข้าด้วยกันด้วย;(เช่นo='';c=0) บางifคำสั่งอาจถูกแทนที่ด้วยการทำดัชนีรายการเพื่อลดความต้องการการแบ่งบรรทัดและแท็บเพิ่มเติม บรรทัดสุดท้ายสามารถใช้ชิ้นo[::-1]แทนที่จะเป็นreversed(o)และ''.joinซ้ำซ้อน คุณอาจจะสามารถเขียนซ้ำเพื่อหลีกเลี่ยงความต้องการreturnงบหลาย ๆ
Jonathan Allan

2
... ถ้าคุณสนใจที่จะมีเคล็ดลับสำหรับการเล่นกอล์ฟในหลามที่นี่
Jonathan Allan

2

JavaScript (ES6), 155 ไบต์

(s,n)=>s.replace(/(-?\d+).?(.*)/,(m,i,d)=>i+'.'+(d+'0'.repeat(++n)).slice(0,n)).replace(/([0-8]?)([.9]*?)\.?(.)$/,(m,n,c,r)=>r>4?-~n+c.replace(/9/g,0):n+c)

คำอธิบาย: สตริงถูกทำให้เป็นมาตรฐานแรกเพื่อให้มี.และn+1เลขทศนิยม ตัวเลขหลักต่อท้าย9s หรือ.s ใด ๆ ที่ก่อนหน้านี้และตัวเลขก่อนหน้านี้ใด ๆ จะถูกพิจารณา หากตัวเลขหลักสุดท้ายมีค่าน้อยกว่า 5 ตัวเลขนั้นและสิ่งใด ๆ ที่เกิดขึ้นก่อนหน้า.นั้นก็จะถูกลบออกทันทีแต่ถ้ามากกว่า 5 9ตัวเลขนั้นจะถูกเปลี่ยนเป็น0s และตัวเลขหลักก่อนหน้าเพิ่มขึ้น (หรือ 1 นำหน้าหากไม่มีเลขก่อนหน้า)



1

สกาลา 44 ไบต์

(s:String,p:Int)=>s"%.${p}f"format s.toFloat

ทดสอบ:

scala> var x = (s:String,p:Int)=>s"%.${p}f"format s.toFloat
x: (String, Int) => String = <function2>

scala> x("14.225",2)
res13: String = 14.23

1

สงสัย 10 ไบต์

@@fix#1E#0

การใช้งาน:

@@fix#1E#0

ตั้งค่าความแม่นยำทศนิยมและเพิ่มศูนย์ต่อท้ายหากจำเป็น


มี TIO สำหรับอันนี้ไหม
Matthias

ไม่มีไม่มี แต่การติดตั้งค่อนข้างง่าย ตรวจสอบให้แน่ใจว่าคุณมี Node.js (v6 +) npm i -g wonderlangและ ใช้wonderคำสั่งเพื่อยิง REPL และวางโค้ดใน
Mama Fun Roll

1

J, 22 17 ไบต์

((10 j.[)]@:":".)

NB.    2    ((10 j.[)]@:":".)   '12.45678'
NB.    12.46 

ขอบคุณ @Conor O'Brien สำหรับการแก้ไขความเข้าใจของฉันเกี่ยวกับกฎ

t=:4 :'(10 j.x)":".y'

    NB.    Examples
    NB.    4 t'12.45678'
    NB.    12.4568
    NB.    4 t'12.456780'
    NB.    12.4568
    NB.    4 t'12.4567801'
    NB.    12.4568
    NB.    2 t'12.45678'
    NB.      12.46
    NB.    2 t'12.4567801'
    NB.      12.46
    NB.    2 (10 j.[)":". '_12.4567801'
    NB.     _12.46

format    
    x t y
where x is a digit number of decimal places required and y
is the character string containing the value to be rounded.

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