Làm tròn chuỗi


10

Một số số thập phân không thể được biểu diễn chính xác dưới dạng float nhị phân do biểu diễn bên trong của số float nhị phân. Ví dụ: làm tròn 14.225 đến hai chữ số thập phân không dẫn đến 14,23 như người ta có thể mong đợi nhưng trong 14,22.

Python :

In: round(14.225, 2)
Out: 14.22

Tuy nhiên, giả sử rằng chúng ta có biểu diễn chuỗi 14.225 là '14 .225 ', chúng ta sẽ có thể đạt được kết quả làm tròn mong muốn '14 .23' dưới dạng biểu diễn chuỗi.

Cách tiếp cận này có thể được khái quát đến độ chính xác tùy ý.

Giải pháp Python 2/3 có thể

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

Hãy thử trực tuyến!

Cách sử dụng :

     # 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

Bài tập

Đối số đầu vào 1 : một chuỗi chứa

  • ít nhất một chữ số ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
  • nhiều nhất một dấu thập phân ( .) phải có trước ít nhất một chữ số,
  • một dấu trừ tùy chọn ( -) làm ký tự đầu tiên.

Đối số đầu vào 2 : số nguyên không âm

Đầu ra : chuỗi được làm tròn chính xác (cơ sở 10)

làm tròn = Làm tròn một nửa từ số không

Đây là một . Số byte thấp nhất sẽ thắng!


@KevinCruijssen 1) Bạn không cần phải dính vào các chuỗi trong phần triển khai của mình và được phép sử dụng tính năng làm tròn tích hợp. Thật không may (đối với câu hỏi), tiêu chuẩn IEEE 754 là một tiêu chuẩn được sử dụng rộng rãi và do đó làm tròn tích hợp sẽ không dẫn đến hành vi mong muốn. 2) Ok, không biết về hộp cát.
Matthias

TI-Basic: round(A,B5 byte
Julian Lachniet 17/03/2017

1
Về đối số đầu vào thứ hai: 0không phải là số nguyên dương, nó là "không âm".
Stewie Griffin

1
Tôi giả sử chúng ta thêm số 0 ở cuối nếu cần? Có lẽ bạn có thể thêm một trường hợp thử nghiệm cho 123.4 & 5 --> 123.40000? Hoặc chúng ta có thể giả sử đầu vào thứ hai sẽ không bao giờ lớn hơn số thập phân sau điểm trong đầu vào đầu tiên?
Kevin Cruijssen 17/03/2017

1
@Matthias Trừ khi bạn có thể tích hợp Python với JavaScript (Tôi chưa bao giờ lập trình Python và hầu như không có JS, vì vậy tôi thực sự không biết nếu có thể) không. Nhưng bạn luôn có thể thêm liên kết Dùng thử trực tuyến với mã kiểm tra của mình. EDIT: Ngoài ra, tốt hơn là nên đợi ít nhất một vài ngày cho đến khi bạn chấp nhận câu trả lời.
Kevin Cruijssen 17/03/2017

Câu trả lời:



5

Perl, 22 20 byte

printf"%.*f",pop,pop

Sử dụng:

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

Đây là phiên bản mã của Dada. Trước:

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

2
printf"%.*f",pop,popnên làm việc
Dada

5

PHP, 33 31 byte

PHP cũng làm tròn chính xác (ít nhất là trên 64 bit):

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

lấy đầu vào từ các đối số dòng lệnh. Chạy với -r.

PHP, không có sẵn, 133 byte

[,$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;

Chạy với -nrhoặc kiểm tra nó trực tuyến .

phá vỡ

[,$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;

Một byte null không hoạt động; vì vậy tôi phải sử dụng substr.


1
Bạn có thể viết "%.$argv[2]f"thay vì "%.{$argv[2]}f", tiết kiệm 2 byte.
Ismael Miguel

4

Hồng ngọc 2,3, 12 + 45 = 57

Sử dụng tích BigDecimalhợp, nhưng nó cần phải được yêu cầu trước khi sử dụng, rẻ hơn để làm cờ.

lá cờ: -rbigdecimal

chức năng:

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

Ruby 2.3 theo mặc định sử dụng ROUND_HALF_UP


4

Javascript (ES6), 44 byte

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

Dùng thử trực tuyến:

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 byte

Đã lưu 5 byte nhờ Kevin Cruijssen
Đã lưu 2 byte nhờ Krazor

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

Hãy thử trực tuyến!


1
from decimal import *và loại bỏ ba d.là ngắn hơn 4 byte.
Kevin Cruijssen 17/03/2017

@KevinCruijssen: Cảm ơn!
Emigna

2
Bạn cũng có thể làm d=Decimald() , điều đó sẽ cứu thêm 5. (Có thể sai, rất buồn ngủ)
FMaz 17/03/2017

@Krazor: Trừ khi tôi làm sai, nó đã tiết kiệm cho tôi 2 byte. Cảm ơn!
Emigna 17/03/2017

Ái chà, đó là những gì tôi muốn nói. Sẽ để lại những suy nghĩ buồn ngủ của tôi lên dù sao đi nữa.
FMaz


3

BASH, 26 23 21 byte

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

sử dụng

lưu vào round_opes.sh, chmod + x round_opes.sh

./round_string.sh 23456789.987654321 3

chỉnh sửa: không cần tải thư viện


Giải thích: bc sử dụng phân quyền tùy ý, tạo tài liệu ở đây với '<<<' thay cho giá trị của thang đo là tham số thứ hai và tham số đầu tiên chia cho 1 để buộc giải thích tỷ lệ.
Marcosm 17/03/2017

2
Điều này mang lại 14.22cho đầu vào 14.225 2, và không14.23
Chấn thương kỹ thuật số

3

AHK, 25 byte

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

Một lần nữa tôi bị cản trở bởi việc AHK không thể sử dụng được truyền trực tiếp vào các tham số trong các hàm chấp nhận tên biến hoặc số. Nếu tôi thay thế abằng 1trong Roundhàm, nó sử dụng giá trị 1. Nếu tôi thử %1%, nó sẽ cố gắng sử dụng nội dung của đối số đầu tiên làm tên biến, không hoạt động. Phải đặt nó làm một biến khác trước tiên làm tôi mất 6 byte.


3

Mẻ, 390 byte

@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%%

Giải trình. Bắt đầu bằng cách trích xuất các dấu hiệu, nếu có. Sau đó, chia số thành số nguyên và chữ số phân số. Phân số được đệm bằng n+1số không để đảm bảo nó có nhiều hơn nchữ số. Chữ nsố thứ (không có chỉ mục) được chia cho 5 và đây là chữ số đầu tiên. Các nchữ số nguyên và phân số được nối với nhau và ký tự được thêm theo ký tự. (Các số 0 bảo vệ bổ sung chống gợn sóng mang.) Sau khi thực hiện dừng gợn, số được tạo lại và bất kỳ dấu thập phân nào được chèn vào.


3

TI-Basic, 53 16 byte

TI-Basic không sử dụng IEEE và phương pháp dưới đây hoạt động cho các vị trí thập phân 0-9 (đã bao gồm).

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

Cảm ơn @JulianLachniet đã chỉ ra rằng các CE CE có toString(lệnh mà tôi không biết (Phiên bản màu calcs OS 5.2 trở lên là bắt buộc).

PS tôi đã có một dòng thứ hai với sub(Str1,1,N+inString(Str1,".nhưng sau đó tôi nhận ra nó là vô dụng.


Làm thế nào được Nsử dụng?
Matthias

@Matthias Cảm ơn bạn đã bắt lỗi chính tả đó! Tôi đã vô tình xóa ba byte cuối cùng với lần chỉnh sửa trước đó của mình
Timtech 18/03/2017

3

Java 7, 77 72 71 byte

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

-1 byte nhờ @cliffroot

Câu trả lời 72 byte:

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

Không giống như Python, Java đã đạn một cách chính xác và đã được trả về một String khi bạn sử dụng String.format("%.2f", aDouble)với các 2thay thế với số tiền thập phân mà bạn muốn.

EDIT / LƯU Ý: Có, tôi biết new Float(n)là ngắn hơn 1 byte new Double(n), nhưng dường như nó không thành công cho các trường hợp thử nghiệm với 123456789.987654321. Xem mã kiểm tra này liên quan đến Double vs Float.

Giải trình:

<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

Mã kiểm tra:

Hãy thử nó ở đây.

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));
    }
  }
}

Đầu ra:

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+""));}
Ngắn

2
Giải pháp này không hoạt động . Mặc dù ví dụ này có khả năng là một vấn đề nửa chẵn / đi-0, các lỗi dấu phẩy động xảy ra và OP đã làm rõ rằng độ chính xác tùy ý nên được hỗ trợ.
CAD97

1
Trong thực tế, bạn thất bại trong các trường hợp ví dụ trong câu hỏi mà bạn đã sao chép ở đây: 123456789.987654321, 4nên 123456789.9877, không phải123456789.9876
CAD97 17/03/2017

2

Python (2/3), 394 byte

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

Làm việc cho các số chính xác tùy ý.


5
Xin chào, và chào mừng bạn đến với PPCG! Tuy nhiên, đây không phải là golf. Có rất nhiều khoảng trắng bạn có thể loại bỏ. Câu trả lời trên trang web này là bắt buộc phải được đánh golf, xin lỗi.
Rɪᴋᴇʀ 17/03/2017

Chỉ một số thứ (có khả năng nhiều hơn nữa) ... Tên hàm có thể là một byte. Dòng đầu tiên có thể sử dụng s[0]<'0'và cũng có thể sử dụng phép nhân chuỗi , m='-'*(s[0]<'0'). Các dòng không có bất kỳ khoảng câu lệnh khối nào có thể được nối cùng với ;(ví dụ o='';c=0). Một số ifcâu lệnh có thể được thay thế bằng cách lập chỉ mục danh sách để giảm thêm nhu cầu ngắt dòng và tab. Dòng cuối cùng có thể sử dụng một lát o[::-1], thay vì reversed(o)''.joinlà dư thừa. Bạn cũng có thể viết lại nó để tránh sự cần thiết của nhiều returncâu lệnh.
Jonathan Allan

2
... Nếu bạn quan tâm, có những mẹo chơi gôn trong Python ở đây .
Jonathan Allan

2

JavaScript (ES6), 155 byte

(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)

Giải thích: Chuỗi đầu tiên được chuẩn hóa để chứa a .n+1chữ số thập phân. Chữ số cuối, bất kỳ 9s hoặc .s trước và bất kỳ chữ số trước, sau đó được xem xét. Nếu chữ số cuối cùng nhỏ hơn 5 thì nó và bất kỳ chữ số nào ngay trước đó .chỉ bị xóa nhưng nếu nó lớn hơn 5 thì 9s được đổi thành0 s và chữ số trước tăng lên (hoặc 1 tiền tố nếu không có chữ số trước).



1

Scala, 44 byte

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

Kiểm tra:

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

Kỳ quan , 10 byte

@@fix#1E#0

Sử dụng:

@@fix#1E#0

Đặt độ chính xác thập phân và thêm các số 0 ở cuối nếu cần.


Có một TIO cho cái này không?
Matthias

Không, không có, nhưng cài đặt khá dễ dàng. Đảm bảo bạn có Node.js (v6 +) và npm i -g wonderlang. Sử dụng wonderlệnh để kích hoạt REPL và dán mã vào.
Mama Fun Roll

1

J, 22 17 byte

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

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

Cảm ơn @Conor O'Brien đã sửa chữa hiểu biết của tôi về các quy tắc.

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.

Thử thách yêu cầu bạn lấy số chữ số sau dấu thập phân để làm tròn thành N số thập phân, không phải N điểm chính xác. Vì vậy, 2 t '1234.456'nên đưa ra 1234.46thay vì6 t '1234.456'
Conor O'Brien
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.