ひもを丸める


10

バイナリフロートの内部表現のため、一部の10進数はバイナリフロートとして正確に表すことができません。たとえば、14.225を2桁の10進数に丸めると、14.23にはなりませんが、14.22になります。

Python

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:含む文字列

  • 少なくとも一桁(0123456789)、
  • .少なくとも1桁の数字が前になければならない最大1つの小数点()、
  • -最初の文字としてのオプションのマイナス()。

入力引数2:非負の整数

出力:正しく丸められた(base 10)文字列

丸め= ゼロから半分に丸める

これはです。最小バイト数が優先されます!


@KevinCruijssen 1)実装の本体で文字列に固執する必要はなく、組み込みの丸めを使用できます。残念ながら(質問として)、IEEE 754標準は広く使用されている標準であるため、組み込みの丸めでは目的の動作が得られません。2)わかりました、サンドボックスを認識していませんでした。
Matthias

TI-Basic:round(A,B5バイト
Julian Lachniet

1
2番目の入力引数に関して:0は正の整数ではなく、「非負」です。
Stewie Griffin

1
必要に応じて後続ゼロを追加すると思いますか?のテストケースを追加していただけます123.4 & 5 --> 123.40000か?または、2番目の入力が最初の入力のポイントの後の小数点以下の桁数を超えることはないと想定できますか?
Kevin Cruijssen 2017年

1
@Matthias PythonをJavaScriptと統合できない限り(私はPythonをプログラミングしたことがなく、JSをプログラミングしたことがないので、可能かどうか正直に知りません)いいえ。ただし、テストコードを使用して、[ オンラインで試す]リンクをいつでも追加できます。編集:また、通常、回答を受け入れるまで少なくとも数日待つことをお勧めします。
Kevin Cruijssen 2017年

回答:



5

Perl、22 20バイト

printf"%.*f",pop,pop

使用:

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

それはダダのバージョンのコードです。前:

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;

nullバイトは機能しません。だから私は使用する必要があります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

パイソン、114の 105 103 96 91 89バイト

Kevin Cruijssenのおかげで5バイト節約Krazorの
おかげで2バイト節約

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

オンラインでお試しください!


1
from decimal import *3つを削除すると、d.4バイト短くなります。
Kevin Cruijssen 2017年

@KevinCruijssen:ありがとう!
Emigna

2
あなたも行うことができますd=Decimalし、d() 保存することになる、別の5(非常に眠い、間違っているかもしれない)
FMaz

@Krazor:私が間違っていない限り、2バイト節約できました。ありがとう!
Emigna

おっと、それは私が意味したことです。とにかく眠そうな考えを残していきます。
FMaz


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は任意の精度を使用し、スケールの値を2番目のパラメーターとして含み、最初のパラメーターを1で割った「<<<」を使用してヒアドキュメントを作成し、スケールの解釈を強制します。
marcosm

2
これは14.22入力のためのもの14.225 2であり、そうではありません14.23
Digital Trauma

3

AHK、25バイト

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

繰り返しになりますが、変数名または数値のいずれかを受け入れる関数で、渡されたパラメーターをAHKで直接使用できないことにうんざりしています。私が交換した場合a1では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ます。nTH(ゼロインデックス付き)桁が5で割った、これは最初のキャリーです。整数とn小数桁が連結され、キャリーが文字ごとに追加されます。(余分なゼロは、キャリーリップルを防ぎます。)キャリーが停止した後、数値が再構築され、小数点が挿入されます。


3

TI-Basic、53 16バイト

TI-BasicはIEEEを使用せず、以下の方法は0〜9(両端を含む)の小数点以下の桁で機能します。

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

CE calcsがtoString(私が知らなかったコマンドを持っていることを示してくれた@JulianLachnietに感謝します(Color Edition calcs OS 5.2以降が必要です)。

PS私はセカンドラインを持ってsub(Str1,1,N+inString(Str1,".いましたが、それからそれが役に立たないことに気付きました。


使い方はN
Matthias

@Matthiasそのタイプミスをキャッチしてくれてありがとう!前の編集で最後の3バイトを誤って削除しました
Timtech

3

Java 7、77 72 71バイト

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

@cliffrootのおかげで-1バイト

72バイトの回答:

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

Pythonとは異なり、Javaはすでに正しく丸められており、必要な小数に置き換えて使用するString.format("%.2f", aDouble)と、すでに文字列を返します2

編集/注:はい、私はnew Float(n)より1バイト短いことを認識しnew Double(n)ていますが、のテストケースでは明らかに失敗し123456789.987654321ます。DoubleとFloatに関するこのテストコードを参照してください。

説明:

<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
1バイト短い:<T>T c(T n,int d){return(T)"".format("%."+d+"f",new Double(n+""));}
cliffroot

2
このソリューションは機能しません。この例は潜在的に丸い半偶数/アウェイ0の問題ですが、浮動小数点エラーが発生するため、OPは任意の精度をサポートする必要があることを明らかにしました。
97年

1
実際、ここで再現した質問の例のケースは失敗します。次のようにする123456789.987654321, 4必要があります123456789.9877123456789.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ɪᴋᴇʀ

ほんのいくつかのこと(おそらくもっとたくさんあります)...関数名は1バイトにすることができます。最初の行ではs[0]<'0'、文字列の乗算を使用できm='-'*(s[0]<'0')ます。ブロックステートメントスパンのない行は、;(などo='';c=0)で結合できます。一部のifステートメントは、おそらく改行やタブの必要性をさらに減らすために、リストのインデックス付けに置き換えることができます。最後の行ではo[::-1]、代わりにスライスを使用できreversed(o)''.joinは冗長です。また、複数のreturnステートメントを必要としないように書き換えることもできます。
ジョナサンアラン


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)

説明:最初にストリングが正規化され、a .n+110進数が含まれます。後続の数字、先行する9sまたは.s、および先行する数字が考慮されます。最後の数字が5未満の場合、その数字と直前の数字は.単純に削除されますが、5より大きい場合、9sはsに変更され0、前の数字が増加します(または前の数字がなかった場合は1が先頭に追加されます)。



1

Scala、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。使用wonderREPLを起動するコマンドを、とのコードを貼り付けます。
ママ楽しいロール

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.

チャレンジでは、小数点以下の桁数を使用して、N桁の精度ではなく、N桁に丸める必要があります。その2 t '1234.456'ため、1234.46代わりに与える必要があります6 t '1234.456'
Conor O'Brien
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.