Satisfying Rounding











up vote
15
down vote

favorite












Satisfying Rounding



You know when you're in science class, and asked to round to 2 sig figs, but your answer is 5.2501...? You should round to 5.3, but that's just so unsatisfying! By rounding to 5.3, you're off by a whole 0.05, which is a large amount compared to 0.1 (the place value you're rounding to)! So help me round in a satisfying way.



To round in a satisfying way, you must round at the first digit you come across that produces a relatively small error - less than half of the maximum error possible when rounding. Basically, you need to round whenever you encounter 0, 1, 8, or 9. If that never happens, return the input as is. Do not round on leading zeroes or ones - that just doesn't feel satisfying.



Input



A string or float value that represents a nonnegative decimal number.



Output



The same decimal number rounded satisfactorily, in either string or float format.



Examples



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


This is a code-golf challenge, so shortest code wins!










share|improve this question
























  • Sandbox
    – Quintec
    2 days ago










  • Are strings such as 036.40000 considered a valid output?
    – Arnauld
    2 days ago






  • 1




    Can we assume that a .0 part will be given for integers? Also, 0 isn't positive.
    – Erik the Outgolfer
    2 days ago










  • @EriktheOutgolfer No, you may not - also thanks, changed to nonnegative.
    – Quintec
    2 days ago










  • @Arnauld No leading nor trailing zeroes, since that kind of defeats the purpose of rounding.
    – Quintec
    2 days ago















up vote
15
down vote

favorite












Satisfying Rounding



You know when you're in science class, and asked to round to 2 sig figs, but your answer is 5.2501...? You should round to 5.3, but that's just so unsatisfying! By rounding to 5.3, you're off by a whole 0.05, which is a large amount compared to 0.1 (the place value you're rounding to)! So help me round in a satisfying way.



To round in a satisfying way, you must round at the first digit you come across that produces a relatively small error - less than half of the maximum error possible when rounding. Basically, you need to round whenever you encounter 0, 1, 8, or 9. If that never happens, return the input as is. Do not round on leading zeroes or ones - that just doesn't feel satisfying.



Input



A string or float value that represents a nonnegative decimal number.



Output



The same decimal number rounded satisfactorily, in either string or float format.



Examples



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


This is a code-golf challenge, so shortest code wins!










share|improve this question
























  • Sandbox
    – Quintec
    2 days ago










  • Are strings such as 036.40000 considered a valid output?
    – Arnauld
    2 days ago






  • 1




    Can we assume that a .0 part will be given for integers? Also, 0 isn't positive.
    – Erik the Outgolfer
    2 days ago










  • @EriktheOutgolfer No, you may not - also thanks, changed to nonnegative.
    – Quintec
    2 days ago










  • @Arnauld No leading nor trailing zeroes, since that kind of defeats the purpose of rounding.
    – Quintec
    2 days ago













up vote
15
down vote

favorite









up vote
15
down vote

favorite











Satisfying Rounding



You know when you're in science class, and asked to round to 2 sig figs, but your answer is 5.2501...? You should round to 5.3, but that's just so unsatisfying! By rounding to 5.3, you're off by a whole 0.05, which is a large amount compared to 0.1 (the place value you're rounding to)! So help me round in a satisfying way.



To round in a satisfying way, you must round at the first digit you come across that produces a relatively small error - less than half of the maximum error possible when rounding. Basically, you need to round whenever you encounter 0, 1, 8, or 9. If that never happens, return the input as is. Do not round on leading zeroes or ones - that just doesn't feel satisfying.



Input



A string or float value that represents a nonnegative decimal number.



Output



The same decimal number rounded satisfactorily, in either string or float format.



Examples



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


This is a code-golf challenge, so shortest code wins!










share|improve this question















Satisfying Rounding



You know when you're in science class, and asked to round to 2 sig figs, but your answer is 5.2501...? You should round to 5.3, but that's just so unsatisfying! By rounding to 5.3, you're off by a whole 0.05, which is a large amount compared to 0.1 (the place value you're rounding to)! So help me round in a satisfying way.



To round in a satisfying way, you must round at the first digit you come across that produces a relatively small error - less than half of the maximum error possible when rounding. Basically, you need to round whenever you encounter 0, 1, 8, or 9. If that never happens, return the input as is. Do not round on leading zeroes or ones - that just doesn't feel satisfying.



Input



A string or float value that represents a nonnegative decimal number.



Output



The same decimal number rounded satisfactorily, in either string or float format.



Examples



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


This is a code-golf challenge, so shortest code wins!







code-golf number rational-numbers






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited yesterday

























asked 2 days ago









Quintec

1,3001519




1,3001519












  • Sandbox
    – Quintec
    2 days ago










  • Are strings such as 036.40000 considered a valid output?
    – Arnauld
    2 days ago






  • 1




    Can we assume that a .0 part will be given for integers? Also, 0 isn't positive.
    – Erik the Outgolfer
    2 days ago










  • @EriktheOutgolfer No, you may not - also thanks, changed to nonnegative.
    – Quintec
    2 days ago










  • @Arnauld No leading nor trailing zeroes, since that kind of defeats the purpose of rounding.
    – Quintec
    2 days ago


















  • Sandbox
    – Quintec
    2 days ago










  • Are strings such as 036.40000 considered a valid output?
    – Arnauld
    2 days ago






  • 1




    Can we assume that a .0 part will be given for integers? Also, 0 isn't positive.
    – Erik the Outgolfer
    2 days ago










  • @EriktheOutgolfer No, you may not - also thanks, changed to nonnegative.
    – Quintec
    2 days ago










  • @Arnauld No leading nor trailing zeroes, since that kind of defeats the purpose of rounding.
    – Quintec
    2 days ago
















Sandbox
– Quintec
2 days ago




Sandbox
– Quintec
2 days ago












Are strings such as 036.40000 considered a valid output?
– Arnauld
2 days ago




Are strings such as 036.40000 considered a valid output?
– Arnauld
2 days ago




1




1




Can we assume that a .0 part will be given for integers? Also, 0 isn't positive.
– Erik the Outgolfer
2 days ago




Can we assume that a .0 part will be given for integers? Also, 0 isn't positive.
– Erik the Outgolfer
2 days ago












@EriktheOutgolfer No, you may not - also thanks, changed to nonnegative.
– Quintec
2 days ago




@EriktheOutgolfer No, you may not - also thanks, changed to nonnegative.
– Quintec
2 days ago












@Arnauld No leading nor trailing zeroes, since that kind of defeats the purpose of rounding.
– Quintec
2 days ago




@Arnauld No leading nor trailing zeroes, since that kind of defeats the purpose of rounding.
– Quintec
2 days ago










5 Answers
5






active

oldest

votes

















up vote
2
down vote













JavaScript (ES6),  100 99 98  78 bytes



Takes input as a string. Returns a float.





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


Try it online!



How?



We first prepend a leading $0$ to the input string, so that we're guaranteed to have a digit before a possible leading $8$ or $9$, that must trigger the rounding right away.



The flag $j$ is set to $1$ as long as we are looking for a digit on which we can do a satisfying rounding, and set to $0$ afterwards.



Because a leading $0$ was added to the string that we're walking through but $s$ was left unchanged, $d$ contains the current character and $s[i]$ is pointing to the next character.



We use the following code to load the next digit in $n$, skipping a possible decimal separator:



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


Although strings are immutable in JavaScript, the expression ++s[i] will return $s[i]+1$ if it contains a numeric value, even though $s[i]$ is not actually incremented. Therefore, the expression !++s[i] is evaluated to $false$ (coerced to $0$) for all digits (including $0$) and to $true$ (coerced to $1$) for the decimal separator ".".



When the rounding occurs, we yield d + --j if the next digit $n$ is $0$ or $1$ (and it's not the leading digit of the original input) and d + j-- if $n$ is $8$ or $9$. Therefore, $j$ is set to $0$ in both cases but we add $0$ to $d$ in the first case (rounding down) and $1$ in the second case (rounding up).






share|improve this answer



















  • 1




    And the pinball/rubber ball falls into a ditch! :)
    – Quintec
    2 days ago


















up vote
2
down vote














Ruby, 79 77 69 67 65 bytes





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


Try it online!



Explanation





  • ->n Take input as a string


  • z=n+".0" Create a temporary string z that is guaranteed to contain a dot and a relevant digit.


  • i=z=~/./ Determine the position of the decimal dot in z and assign to i.


  • z[i]='' Drop the dot so that it doesn't get in the way further on.


  • z=~/(?!^)[01]|8|9/ Determine the position of non-starting 0-1 or any 8-9, whichever comes first.


  • (...)-i This difference will be the number of decimal places to keep, negative if we will be rounding left of the dot.


  • n.to_f.round ... Convert to float and do the rounding.






share|improve this answer






























    up vote
    1
    down vote














    Jelly, 34 bytes



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


    Try it online!



    -1 thanks to Jonathan Allan.






    share|improve this answer























    • Why ŒV? I think V will work too.
      – Jonathan Allan
      2 days ago










    • @JonathanAllan Nope. (basically banker's rounding quirks)
      – Erik the Outgolfer
      2 days ago












    • Oh, because it's not acting on the input? Try _>¥0ɓVær like mine is (I missed usage of the dyadic quick so thanks too!)
      – Jonathan Allan
      2 days ago










    • @JonathanAllan Ah, clever usage of chains, thanks.
      – Erik the Outgolfer
      2 days ago


















    up vote
    1
    down vote














    Jelly,  30  29 bytes



    -1 thanks to Erik the Outgolfer (use of dyadic quick ¥ from his answer)



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


    A monadic link accepting a list of characters which yields a float.



    Try it online! Or see the test-suite.



    How



    First note that the input string is made exclusively from the characters 0123456789. which have ordinals [48,49,50,51,52,53,54,55,56,57,46], which have remainders when divided by eight of [0,1,2,3,4,5,6,7,0,1,6]. The only characters which are between -1 and 1 inclusive are 0, 1, 8, and 9.



    Furthermore if we subtract eight from the ordinals ([40,41,42,43,44,45,46,47,48,49,38]) the same (fairly obviously) holds. If we halve these ([20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19]) the only characters which have remainders when divided by eight which are between -1 and 1 inclusive are 8 and 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)





    share|improve this answer






























      up vote
      1
      down vote














      Retina 0.8.2, 75 bytes



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


      Try it online! Link includes test cases. Explanation:



      ^[89]
      10


      Handle the case of a leading 8 or 9.



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


      If there's a non-leading 0 or 1, then zero it and the rest of the string out. Also, if there's an 8 or 9, then leave it, but zero out the rest of the string. (But leave the decimal point unchanged in either case.)



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


      If there's still an 8 or a 9 at this point, then zero it out, and increment the preceding digit (possibly before the decimal point).



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


      Delete trailing zeros if they are after a decimal point, but only delete the decimal point if there are no other digits in between.






      share|improve this answer





















        Your Answer





        StackExchange.ifUsing("editor", function () {
        return StackExchange.using("mathjaxEditing", function () {
        StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
        StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
        });
        });
        }, "mathjax-editing");

        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "200"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        convertImagesToLinks: false,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: null,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodegolf.stackexchange.com%2fquestions%2f177203%2fsatisfying-rounding%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        5 Answers
        5






        active

        oldest

        votes








        5 Answers
        5






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes








        up vote
        2
        down vote













        JavaScript (ES6),  100 99 98  78 bytes



        Takes input as a string. Returns a float.





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


        Try it online!



        How?



        We first prepend a leading $0$ to the input string, so that we're guaranteed to have a digit before a possible leading $8$ or $9$, that must trigger the rounding right away.



        The flag $j$ is set to $1$ as long as we are looking for a digit on which we can do a satisfying rounding, and set to $0$ afterwards.



        Because a leading $0$ was added to the string that we're walking through but $s$ was left unchanged, $d$ contains the current character and $s[i]$ is pointing to the next character.



        We use the following code to load the next digit in $n$, skipping a possible decimal separator:



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


        Although strings are immutable in JavaScript, the expression ++s[i] will return $s[i]+1$ if it contains a numeric value, even though $s[i]$ is not actually incremented. Therefore, the expression !++s[i] is evaluated to $false$ (coerced to $0$) for all digits (including $0$) and to $true$ (coerced to $1$) for the decimal separator ".".



        When the rounding occurs, we yield d + --j if the next digit $n$ is $0$ or $1$ (and it's not the leading digit of the original input) and d + j-- if $n$ is $8$ or $9$. Therefore, $j$ is set to $0$ in both cases but we add $0$ to $d$ in the first case (rounding down) and $1$ in the second case (rounding up).






        share|improve this answer



















        • 1




          And the pinball/rubber ball falls into a ditch! :)
          – Quintec
          2 days ago















        up vote
        2
        down vote













        JavaScript (ES6),  100 99 98  78 bytes



        Takes input as a string. Returns a float.





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


        Try it online!



        How?



        We first prepend a leading $0$ to the input string, so that we're guaranteed to have a digit before a possible leading $8$ or $9$, that must trigger the rounding right away.



        The flag $j$ is set to $1$ as long as we are looking for a digit on which we can do a satisfying rounding, and set to $0$ afterwards.



        Because a leading $0$ was added to the string that we're walking through but $s$ was left unchanged, $d$ contains the current character and $s[i]$ is pointing to the next character.



        We use the following code to load the next digit in $n$, skipping a possible decimal separator:



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


        Although strings are immutable in JavaScript, the expression ++s[i] will return $s[i]+1$ if it contains a numeric value, even though $s[i]$ is not actually incremented. Therefore, the expression !++s[i] is evaluated to $false$ (coerced to $0$) for all digits (including $0$) and to $true$ (coerced to $1$) for the decimal separator ".".



        When the rounding occurs, we yield d + --j if the next digit $n$ is $0$ or $1$ (and it's not the leading digit of the original input) and d + j-- if $n$ is $8$ or $9$. Therefore, $j$ is set to $0$ in both cases but we add $0$ to $d$ in the first case (rounding down) and $1$ in the second case (rounding up).






        share|improve this answer



















        • 1




          And the pinball/rubber ball falls into a ditch! :)
          – Quintec
          2 days ago













        up vote
        2
        down vote










        up vote
        2
        down vote









        JavaScript (ES6),  100 99 98  78 bytes



        Takes input as a string. Returns a float.





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


        Try it online!



        How?



        We first prepend a leading $0$ to the input string, so that we're guaranteed to have a digit before a possible leading $8$ or $9$, that must trigger the rounding right away.



        The flag $j$ is set to $1$ as long as we are looking for a digit on which we can do a satisfying rounding, and set to $0$ afterwards.



        Because a leading $0$ was added to the string that we're walking through but $s$ was left unchanged, $d$ contains the current character and $s[i]$ is pointing to the next character.



        We use the following code to load the next digit in $n$, skipping a possible decimal separator:



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


        Although strings are immutable in JavaScript, the expression ++s[i] will return $s[i]+1$ if it contains a numeric value, even though $s[i]$ is not actually incremented. Therefore, the expression !++s[i] is evaluated to $false$ (coerced to $0$) for all digits (including $0$) and to $true$ (coerced to $1$) for the decimal separator ".".



        When the rounding occurs, we yield d + --j if the next digit $n$ is $0$ or $1$ (and it's not the leading digit of the original input) and d + j-- if $n$ is $8$ or $9$. Therefore, $j$ is set to $0$ in both cases but we add $0$ to $d$ in the first case (rounding down) and $1$ in the second case (rounding up).






        share|improve this answer














        JavaScript (ES6),  100 99 98  78 bytes



        Takes input as a string. Returns a float.





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


        Try it online!



        How?



        We first prepend a leading $0$ to the input string, so that we're guaranteed to have a digit before a possible leading $8$ or $9$, that must trigger the rounding right away.



        The flag $j$ is set to $1$ as long as we are looking for a digit on which we can do a satisfying rounding, and set to $0$ afterwards.



        Because a leading $0$ was added to the string that we're walking through but $s$ was left unchanged, $d$ contains the current character and $s[i]$ is pointing to the next character.



        We use the following code to load the next digit in $n$, skipping a possible decimal separator:



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


        Although strings are immutable in JavaScript, the expression ++s[i] will return $s[i]+1$ if it contains a numeric value, even though $s[i]$ is not actually incremented. Therefore, the expression !++s[i] is evaluated to $false$ (coerced to $0$) for all digits (including $0$) and to $true$ (coerced to $1$) for the decimal separator ".".



        When the rounding occurs, we yield d + --j if the next digit $n$ is $0$ or $1$ (and it's not the leading digit of the original input) and d + j-- if $n$ is $8$ or $9$. Therefore, $j$ is set to $0$ in both cases but we add $0$ to $d$ in the first case (rounding down) and $1$ in the second case (rounding up).







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited yesterday

























        answered 2 days ago









        Arnauld

        70.9k688298




        70.9k688298








        • 1




          And the pinball/rubber ball falls into a ditch! :)
          – Quintec
          2 days ago














        • 1




          And the pinball/rubber ball falls into a ditch! :)
          – Quintec
          2 days ago








        1




        1




        And the pinball/rubber ball falls into a ditch! :)
        – Quintec
        2 days ago




        And the pinball/rubber ball falls into a ditch! :)
        – Quintec
        2 days ago










        up vote
        2
        down vote














        Ruby, 79 77 69 67 65 bytes





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


        Try it online!



        Explanation





        • ->n Take input as a string


        • z=n+".0" Create a temporary string z that is guaranteed to contain a dot and a relevant digit.


        • i=z=~/./ Determine the position of the decimal dot in z and assign to i.


        • z[i]='' Drop the dot so that it doesn't get in the way further on.


        • z=~/(?!^)[01]|8|9/ Determine the position of non-starting 0-1 or any 8-9, whichever comes first.


        • (...)-i This difference will be the number of decimal places to keep, negative if we will be rounding left of the dot.


        • n.to_f.round ... Convert to float and do the rounding.






        share|improve this answer



























          up vote
          2
          down vote














          Ruby, 79 77 69 67 65 bytes





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


          Try it online!



          Explanation





          • ->n Take input as a string


          • z=n+".0" Create a temporary string z that is guaranteed to contain a dot and a relevant digit.


          • i=z=~/./ Determine the position of the decimal dot in z and assign to i.


          • z[i]='' Drop the dot so that it doesn't get in the way further on.


          • z=~/(?!^)[01]|8|9/ Determine the position of non-starting 0-1 or any 8-9, whichever comes first.


          • (...)-i This difference will be the number of decimal places to keep, negative if we will be rounding left of the dot.


          • n.to_f.round ... Convert to float and do the rounding.






          share|improve this answer

























            up vote
            2
            down vote










            up vote
            2
            down vote










            Ruby, 79 77 69 67 65 bytes





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


            Try it online!



            Explanation





            • ->n Take input as a string


            • z=n+".0" Create a temporary string z that is guaranteed to contain a dot and a relevant digit.


            • i=z=~/./ Determine the position of the decimal dot in z and assign to i.


            • z[i]='' Drop the dot so that it doesn't get in the way further on.


            • z=~/(?!^)[01]|8|9/ Determine the position of non-starting 0-1 or any 8-9, whichever comes first.


            • (...)-i This difference will be the number of decimal places to keep, negative if we will be rounding left of the dot.


            • n.to_f.round ... Convert to float and do the rounding.






            share|improve this answer















            Ruby, 79 77 69 67 65 bytes





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


            Try it online!



            Explanation





            • ->n Take input as a string


            • z=n+".0" Create a temporary string z that is guaranteed to contain a dot and a relevant digit.


            • i=z=~/./ Determine the position of the decimal dot in z and assign to i.


            • z[i]='' Drop the dot so that it doesn't get in the way further on.


            • z=~/(?!^)[01]|8|9/ Determine the position of non-starting 0-1 or any 8-9, whichever comes first.


            • (...)-i This difference will be the number of decimal places to keep, negative if we will be rounding left of the dot.


            • n.to_f.round ... Convert to float and do the rounding.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited yesterday

























            answered 2 days ago









            Kirill L.

            3,4051118




            3,4051118






















                up vote
                1
                down vote














                Jelly, 34 bytes



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


                Try it online!



                -1 thanks to Jonathan Allan.






                share|improve this answer























                • Why ŒV? I think V will work too.
                  – Jonathan Allan
                  2 days ago










                • @JonathanAllan Nope. (basically banker's rounding quirks)
                  – Erik the Outgolfer
                  2 days ago












                • Oh, because it's not acting on the input? Try _>¥0ɓVær like mine is (I missed usage of the dyadic quick so thanks too!)
                  – Jonathan Allan
                  2 days ago










                • @JonathanAllan Ah, clever usage of chains, thanks.
                  – Erik the Outgolfer
                  2 days ago















                up vote
                1
                down vote














                Jelly, 34 bytes



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


                Try it online!



                -1 thanks to Jonathan Allan.






                share|improve this answer























                • Why ŒV? I think V will work too.
                  – Jonathan Allan
                  2 days ago










                • @JonathanAllan Nope. (basically banker's rounding quirks)
                  – Erik the Outgolfer
                  2 days ago












                • Oh, because it's not acting on the input? Try _>¥0ɓVær like mine is (I missed usage of the dyadic quick so thanks too!)
                  – Jonathan Allan
                  2 days ago










                • @JonathanAllan Ah, clever usage of chains, thanks.
                  – Erik the Outgolfer
                  2 days ago













                up vote
                1
                down vote










                up vote
                1
                down vote










                Jelly, 34 bytes



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


                Try it online!



                -1 thanks to Jonathan Allan.






                share|improve this answer















                Jelly, 34 bytes



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


                Try it online!



                -1 thanks to Jonathan Allan.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited 2 days ago

























                answered 2 days ago









                Erik the Outgolfer

                31k429102




                31k429102












                • Why ŒV? I think V will work too.
                  – Jonathan Allan
                  2 days ago










                • @JonathanAllan Nope. (basically banker's rounding quirks)
                  – Erik the Outgolfer
                  2 days ago












                • Oh, because it's not acting on the input? Try _>¥0ɓVær like mine is (I missed usage of the dyadic quick so thanks too!)
                  – Jonathan Allan
                  2 days ago










                • @JonathanAllan Ah, clever usage of chains, thanks.
                  – Erik the Outgolfer
                  2 days ago


















                • Why ŒV? I think V will work too.
                  – Jonathan Allan
                  2 days ago










                • @JonathanAllan Nope. (basically banker's rounding quirks)
                  – Erik the Outgolfer
                  2 days ago












                • Oh, because it's not acting on the input? Try _>¥0ɓVær like mine is (I missed usage of the dyadic quick so thanks too!)
                  – Jonathan Allan
                  2 days ago










                • @JonathanAllan Ah, clever usage of chains, thanks.
                  – Erik the Outgolfer
                  2 days ago
















                Why ŒV? I think V will work too.
                – Jonathan Allan
                2 days ago




                Why ŒV? I think V will work too.
                – Jonathan Allan
                2 days ago












                @JonathanAllan Nope. (basically banker's rounding quirks)
                – Erik the Outgolfer
                2 days ago






                @JonathanAllan Nope. (basically banker's rounding quirks)
                – Erik the Outgolfer
                2 days ago














                Oh, because it's not acting on the input? Try _>¥0ɓVær like mine is (I missed usage of the dyadic quick so thanks too!)
                – Jonathan Allan
                2 days ago




                Oh, because it's not acting on the input? Try _>¥0ɓVær like mine is (I missed usage of the dyadic quick so thanks too!)
                – Jonathan Allan
                2 days ago












                @JonathanAllan Ah, clever usage of chains, thanks.
                – Erik the Outgolfer
                2 days ago




                @JonathanAllan Ah, clever usage of chains, thanks.
                – Erik the Outgolfer
                2 days ago










                up vote
                1
                down vote














                Jelly,  30  29 bytes



                -1 thanks to Erik the Outgolfer (use of dyadic quick ¥ from his answer)



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


                A monadic link accepting a list of characters which yields a float.



                Try it online! Or see the test-suite.



                How



                First note that the input string is made exclusively from the characters 0123456789. which have ordinals [48,49,50,51,52,53,54,55,56,57,46], which have remainders when divided by eight of [0,1,2,3,4,5,6,7,0,1,6]. The only characters which are between -1 and 1 inclusive are 0, 1, 8, and 9.



                Furthermore if we subtract eight from the ordinals ([40,41,42,43,44,45,46,47,48,49,38]) the same (fairly obviously) holds. If we halve these ([20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19]) the only characters which have remainders when divided by eight which are between -1 and 1 inclusive are 8 and 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)





                share|improve this answer



























                  up vote
                  1
                  down vote














                  Jelly,  30  29 bytes



                  -1 thanks to Erik the Outgolfer (use of dyadic quick ¥ from his answer)



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


                  A monadic link accepting a list of characters which yields a float.



                  Try it online! Or see the test-suite.



                  How



                  First note that the input string is made exclusively from the characters 0123456789. which have ordinals [48,49,50,51,52,53,54,55,56,57,46], which have remainders when divided by eight of [0,1,2,3,4,5,6,7,0,1,6]. The only characters which are between -1 and 1 inclusive are 0, 1, 8, and 9.



                  Furthermore if we subtract eight from the ordinals ([40,41,42,43,44,45,46,47,48,49,38]) the same (fairly obviously) holds. If we halve these ([20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19]) the only characters which have remainders when divided by eight which are between -1 and 1 inclusive are 8 and 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)





                  share|improve this answer

























                    up vote
                    1
                    down vote










                    up vote
                    1
                    down vote










                    Jelly,  30  29 bytes



                    -1 thanks to Erik the Outgolfer (use of dyadic quick ¥ from his answer)



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


                    A monadic link accepting a list of characters which yields a float.



                    Try it online! Or see the test-suite.



                    How



                    First note that the input string is made exclusively from the characters 0123456789. which have ordinals [48,49,50,51,52,53,54,55,56,57,46], which have remainders when divided by eight of [0,1,2,3,4,5,6,7,0,1,6]. The only characters which are between -1 and 1 inclusive are 0, 1, 8, and 9.



                    Furthermore if we subtract eight from the ordinals ([40,41,42,43,44,45,46,47,48,49,38]) the same (fairly obviously) holds. If we halve these ([20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19]) the only characters which have remainders when divided by eight which are between -1 and 1 inclusive are 8 and 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)





                    share|improve this answer















                    Jelly,  30  29 bytes



                    -1 thanks to Erik the Outgolfer (use of dyadic quick ¥ from his answer)



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


                    A monadic link accepting a list of characters which yields a float.



                    Try it online! Or see the test-suite.



                    How



                    First note that the input string is made exclusively from the characters 0123456789. which have ordinals [48,49,50,51,52,53,54,55,56,57,46], which have remainders when divided by eight of [0,1,2,3,4,5,6,7,0,1,6]. The only characters which are between -1 and 1 inclusive are 0, 1, 8, and 9.



                    Furthermore if we subtract eight from the ordinals ([40,41,42,43,44,45,46,47,48,49,38]) the same (fairly obviously) holds. If we halve these ([20,20.5,21,21.5,22,22.5,23,23.5,24,24.5,19]) the only characters which have remainders when divided by eight which are between -1 and 1 inclusive are 8 and 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)






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited 2 days ago

























                    answered 2 days ago









                    Jonathan Allan

                    50.5k534165




                    50.5k534165






















                        up vote
                        1
                        down vote














                        Retina 0.8.2, 75 bytes



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


                        Try it online! Link includes test cases. Explanation:



                        ^[89]
                        10


                        Handle the case of a leading 8 or 9.



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


                        If there's a non-leading 0 or 1, then zero it and the rest of the string out. Also, if there's an 8 or 9, then leave it, but zero out the rest of the string. (But leave the decimal point unchanged in either case.)



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


                        If there's still an 8 or a 9 at this point, then zero it out, and increment the preceding digit (possibly before the decimal point).



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


                        Delete trailing zeros if they are after a decimal point, but only delete the decimal point if there are no other digits in between.






                        share|improve this answer

























                          up vote
                          1
                          down vote














                          Retina 0.8.2, 75 bytes



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


                          Try it online! Link includes test cases. Explanation:



                          ^[89]
                          10


                          Handle the case of a leading 8 or 9.



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


                          If there's a non-leading 0 or 1, then zero it and the rest of the string out. Also, if there's an 8 or 9, then leave it, but zero out the rest of the string. (But leave the decimal point unchanged in either case.)



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


                          If there's still an 8 or a 9 at this point, then zero it out, and increment the preceding digit (possibly before the decimal point).



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


                          Delete trailing zeros if they are after a decimal point, but only delete the decimal point if there are no other digits in between.






                          share|improve this answer























                            up vote
                            1
                            down vote










                            up vote
                            1
                            down vote










                            Retina 0.8.2, 75 bytes



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


                            Try it online! Link includes test cases. Explanation:



                            ^[89]
                            10


                            Handle the case of a leading 8 or 9.



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


                            If there's a non-leading 0 or 1, then zero it and the rest of the string out. Also, if there's an 8 or 9, then leave it, but zero out the rest of the string. (But leave the decimal point unchanged in either case.)



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


                            If there's still an 8 or a 9 at this point, then zero it out, and increment the preceding digit (possibly before the decimal point).



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


                            Delete trailing zeros if they are after a decimal point, but only delete the decimal point if there are no other digits in between.






                            share|improve this answer













                            Retina 0.8.2, 75 bytes



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


                            Try it online! Link includes test cases. Explanation:



                            ^[89]
                            10


                            Handle the case of a leading 8 or 9.



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


                            If there's a non-leading 0 or 1, then zero it and the rest of the string out. Also, if there's an 8 or 9, then leave it, but zero out the rest of the string. (But leave the decimal point unchanged in either case.)



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


                            If there's still an 8 or a 9 at this point, then zero it out, and increment the preceding digit (possibly before the decimal point).



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


                            Delete trailing zeros if they are after a decimal point, but only delete the decimal point if there are no other digits in between.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered 2 days ago









                            Neil

                            78.6k744175




                            78.6k744175






























                                draft saved

                                draft discarded




















































                                If this is an answer to a challenge…




                                • …Be sure to follow the challenge specification. However, please refrain from exploiting obvious loopholes. Answers abusing any of the standard loopholes are considered invalid. If you think a specification is unclear or underspecified, comment on the question instead.


                                • …Try to optimize your score. For instance, answers to code-golf challenges should attempt to be as short as possible. You can always include a readable version of the code in addition to the competitive one.
                                  Explanations of your answer make it more interesting to read and are very much encouraged.


                                • …Include a short header which indicates the language(s) of your code and its score, as defined by the challenge.



                                More generally…




                                • …Please make sure to answer the question and provide sufficient detail.


                                • …Avoid asking for help, clarification or responding to other answers (use comments instead).






                                Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                Please pay close attention to the following guidance:


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodegolf.stackexchange.com%2fquestions%2f177203%2fsatisfying-rounding%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Plaza Victoria

                                Brian Clough

                                Cáceres