Удовлетворительное округление

16

Удовлетворительное округление

Вы знаете, когда вы находитесь в классе науки, и попросили округлить до 2 сиг фиг, но ваш ответ 5.2501...? Вы должны округлить до 5.3, но это так неудовлетворительно! При округлении до 5.3вы получаете целые 0,05, что является большим значением по сравнению с 0,1 (значение места, к которому вы округляете)! Так что помогите мне с удовлетворением.

Чтобы выполнить округление удовлетворительным образом, необходимо выполнить округление по первой найденной цифре, которая дает относительно небольшую ошибку - менее половины максимально возможной ошибки при округлении. По сути, вам нужно округлять каждый раз, когда вы сталкиваетесь с 0, 1, 8 или 9. Если этого никогда не происходит, вернуть входные данные как есть. Не округляйте ведущие нули или единицы - это просто не приносит удовлетворения.

вход

Строка или значение с плавающей запятой, которое представляет неотрицательное десятичное число.

Выход

Одно и то же десятичное число округляется удовлетворительно в формате строки или числа с плавающей запятой.

Примеры

Input -> Output
0 -> 0
0.5 -> 0.5
0.19 -> 0
0.8 -> 1
5.64511 -> 5.645
18.913 -> 20
88.913 -> 100
36.38299 -> 36.4
621 -> 620
803.22 -> 1000
547.4726 -> 547.4726

Это испытание , поэтому выигрывает самый короткий код!

Quintec
источник
Строки, которые 036.40000считаются допустимыми, считаются?
Арно
1
Можем ли мы предположить, что .0часть будет дана для целых чисел? Кроме того, 0не является положительным.
Эрик Outgolfer
@EriktheOutgolfer Нет, вы не можете - также спасибо, изменилось на неотрицательное.
Quintec
1
Так 19раундов, 20но 0.19раундов 0? Почему?
Нил

Ответы:

2

JavaScript (ES6),  100 99 98  78 байт

Принимает ввод в виде строки. Возвращает поплавок.

s=>+(0+s).replace(/\d/g,(d,i)=>j&&+d+((n=s[i+!++s[i]])<2&&i?--j:n>7&&j--),j=1)

Попробуйте онлайн!

Как?

Сначала мы добавляем начальный 0 к входной строке, чтобы у нас была гарантированная цифра перед возможным начальным 8 или 9 должна , которая должна сразу же вызвать округление.

Флаг J устанавливается в 1 пока мы ищем цифру, по которой мы можем выполнить удовлетворительное округление, и затем устанавливается в 0 .

Поскольку в строку, по которой мы идем, был добавлен начальный 0 но s был оставлен без изменений, d содержит текущий символ, а s[я] указывает на следующий символ.

Мы используем следующий код для загрузки следующей цифры в N , пропуская возможный десятичный разделитель:

n = s[i + !++s[i]]

Хотя строки в JavaScript являются неизменяемыми, выражение ++s[i]вернет s[я]+1 если оно содержит числовое значение, даже если s[я] фактически не увеличивается. Таким образом, выражение !++s[i]оценивается в еaLsе (принуждаемого к 0 ) для всех цифр (включая 0 ) , а TрUе (принуждают к 1 ) для десятичного разделителя ".".

d + --jN01d + j--N89J00d1

Arnauld
источник
1
И пинбол / резиновый мяч падает в канаву! :)
Quintec
2

Ruby , 79 77 69 67 65 байт

->n,z=n+".0"{z[i=z=~/\./]='';n.to_f.round (z=~/(?!^)[01]|8|9/)-i}

Попробуйте онлайн!

объяснение

  • ->n Принять ввод как строку
  • z=n+".0"Создайте временную строку, zкоторая гарантированно содержит точку и соответствующую цифру.
  • i=z=~/\./Определите положение десятичной точки в zи назначьте i.
  • z[i]='' Опустите точку, чтобы она не мешала дальше.
  • z=~/(?!^)[01]|8|9/Определите положение не запускается 0-1или любой 8-9, в зависимости от того, что наступит раньше.
  • (...)-i Эта разница будет числом десятичных разрядов, которое будет сохраняться, отрицательным, если мы будем округлять левую точку.
  • n.to_f.round ... Конвертировать, чтобы плавать и делать округления.
Кирилл Л.
источник
1

Желе , 34 байта

;”.ḟ$µ»"”2e€⁽¡XṾ¤;1i1_i”.$_>¥0ɓVær

Попробуйте онлайн!

-1 спасибо Джонатану Аллану .

Эрик Outgolfer
источник
Почему ŒV? Я думаю, что Vбудет работать тоже.
Джонатан Аллан
@JonathanAllan Нет. (в основном
причуда
О, потому что это не действует на входе? Попробуйте, _>¥0ɓVærкак у меня (я пропустил использование диадической быстрой, так что спасибо тоже!)
Джонатан Аллан
@JonathanAllan Ах, умное использование цепочек, спасибо.
Эрик Outgolfer
1

Желе ,  30  29 байт

-1 спасибо Эрику Аутгольферу (использование диадического слова быстро ¥из его ответа)

O;0µ_8H1¦%8ỊTḢ_<48TḢƊ_>¥0ɓVær

Монадическая ссылка, принимающая список символов, который приводит к плавающей запятой.

Попробуйте онлайн! Или увидеть набор тестов .

Как

Прежде всего обратите внимание, что входная строка состоит исключительно из символов, 0123456789.имеющих порядковые номера [48,49,50,51,52,53,54,55,56,57,46], которые имеют остатки при делении на восемь [0,1,2,3,4,5,6,7,0,1,6]. Только символы , которые находятся между -1и 1включительно 0, 1, 8и 9.

Кроме того, если мы вычтем восемь из ординалов ( [40,41,42,43,44,45,46,47,48,49,38]), то же самое (довольно очевидно) выполнено. Если мы делим их пополам ( [20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19]), то единственными символами, у которых есть остатки при делении на восемь, между ними -1и 1включительно, являются 8и 9.

O;0µ_8H1¦%8ỊTḢ_<48TḢƊ_>¥0ɓVær - Link: list of characters, S
O                             - ordinal (vectorises across S)
 ;0                           - concatenate a zero
                              - (to cater BOTH for no '0', '1', '8', or '9' AND for no '.')
   µ                          - start a new monadic link (call that X)
    _8                        - subtract eight (vectorises across X)
        ¦                     - sparse application...
       1                      - ...to: indices: one
      H                       - ...do: halve (i.e. halve first ordinal)
         %8                   - modulo by eight (vectorises)
           Ị                  - insignificant (abs(v)<=1?) (vectorises)
            T                 - truthy indices
             Ḣ                - head
                    Ɗ         - last three links as a monad (i.e. f(X)):
               <48            -   less than 48? (i.e. was it a '.' in S or the added 0?)
                  T           -   truthy indices
                   Ḣ          -   head
              _               - subtract
                       ¥      - last two links as a dyad
                      < 0     -   less than zero? (1 if so 0 otherwise)
                     _        -   subtract
                         ɓ    - start a new dyadic chain (i.e. f(S,X))
                          V   - evaluate S as Jelly code (i.e. get S as a float)
                           ær - round to the nearest multiple of 10^(-X)
Джонатан Аллан
источник
1

Сетчатка 0.8.2 , 75 байт

^[89]
10
T`d`0`(?<=.)[01].*|(?<=8|9).*
T`89d`0d`.\.?[89]
(\.|(\..+?))0+$
$2

Попробуйте онлайн! Ссылка включает в себя тестовые случаи. Объяснение:

^[89]
10

Ручка ведущий ведущий 8или 9.

T`d`0`(?<=.)[01].*|(?<=8|9).*

Если есть не ведущий 0или 1, то обнулите его и оставшуюся часть строки. Кроме того, если есть 8или 9, оставьте его, но обнулите оставшуюся часть строки. (Но оставьте десятичную точку без изменений в любом случае.)

T`89d`0d`.\.?[89]

Если в этой точке все еще есть 8или или 9, то обнулите его и увеличьте предыдущую цифру (возможно, до десятичной точки).

(\.|(\..+?))0+$
$2

Удалите конечные нули, если они идут после десятичной точки, но удаляйте только десятичную точку, если между ними нет других цифр.

Нил
источник
1

C (gcc) , 111 102 байта

g(_,i,j,k)char*_;{for(i=*_<56?*_++:48,j=3;j;j&=k%8>1|(i=*_++)/48*2)putchar(j&1?i+(k=_[*_<48])/56:48);}

Попробуйте онлайн!

//_: input, as string
//i: current digit, rounded if applicable
//j: tracks whether number is rounded, and whether \0 or '.' has been encountered
//k: digit to test rounding (round if k is one of 0,1,8,9)
//'0'==48, '8'==56
g(_,i,j,k)char*_;{
    for(i=*_<56?*_++:48,j=3;                //special case: if first digit is 8 or 9, use a
                                            //placeholder digit with value 0. initialize j.
        j;                                  //only stop execution when number is rounded and
                                            //'.' or \0 has been encountered.
        j&=k%8>1|(i=*_++)/48*2)             //check if execution should stop.
        putchar(j&1?i+(k=_[*_<48])/56:48);  //print '0' if rounding had already been done;
                                            //otherwise, print digit. round up as needed.
}
attinat
источник
0

C # (интерактивный компилятор Visual C #) , 280 байт

c=>{int d=c.IndexOf('.');int t=c.IndexOfAny(new char[]{'8','9','0','1'},1);var m=c[0]=='8'||c[0]=='9'?1>0:0>1;var z=decimal.Parse(c);Func<decimal>q=()=>(decimal)Math.Pow(10,m?d<0?c.Length:d:d<0?c.Length-t:d>t?d-t:d-t+1);return m?Math.Round(z/q())*q():t<0?z:Math.Round(z/q())*q();}

Попробуйте онлайн!

Это может быть короче, если я использую двойные вместо десятичных, но я использовал десятичные для сохранения точности, иначе число, такое как 547.4726 будет 547.472595214844.

C # (интерактивный компилятор Visual C #) , 268 байт

c=>{int d=c.IndexOf('.');int t=c.IndexOfAny(new char[]{'8','9','0','1'},1);var m=c[0]=='8'||c[0]=='9'?1>0:0>1;var z=float.Parse(c);Func<double>q=()=>Math.Pow(10,m?d<0?c.Length:d:d<0?c.Length-t:d>t?d-t:d-t+1);return m?Math.Round(z/q())*q():t<0?z:Math.Round(z/q())*q();}

Попробуйте онлайн! (Менее точная версия)

Воплощение невежества
источник