Rounding/parsing decimal vs float

Wednesday, 1 November 2017 · 5 messages
ML
Marco Lettere1 Nov 2017 12:18 #
Hi all, I thought of asking this in parallel of hacking my own parsing procedure ... Is there a native way to parse scientific notation string into xs:decimal since a direct casting (xs:decimal("1e1")) is not allowed? Thanks, Marco.
KK
Kristian Kankainen1 Nov 2017 12:57 #
You need to use xs:float or xs:double instead of xs:decimal to be able to use the 'e' or 'E' as the exponent separator. Br, Kristian K1. nov 2017 13:18 kirjutas kuupäeval Marco Lettere <m.lettere at gmail.com>:
Quoted text · Marco Lettere · 13 lines
> > Hi all, > > I thought of asking this in parallel of hacking my own parsing procedure > ... > > Is there a native way to parse scientific notation string into > xs:decimal since a direct casting (xs:decimal("1e1")) is not allowed? > > Thanks, > > Marco. >
ML
Marco Lettere1 Nov 2017 13:21 #
Thanks Kristian, unfortunately this introduces rounding errors which I'm trying to avoid because managing units, measures and monetary amounts. M. Il 01 nov 2017 12:57 PM, "Kristian Kankainen" <kristian at keeleleek.ee> ha scritto: You need to use xs:float or xs:double instead of xs:decimal to be able to use the 'e' or 'E' as the exponent separator. Br, Kristian K1. nov 2017 13:18 kirjutas kuupäeval Marco Lettere < m.lettere at gmail.com>:
Quoted text · Kristian Kankainen · 13 lines
> > Hi all, > > I thought of asking this in parallel of hacking my own parsing procedure > ... > > Is there a native way to parse scientific notation string into > xs:decimal since a direct casting (xs:decimal("1e1")) is not allowed? > > Thanks, > > Marco. >
LW
Leonard Wörteler1 Nov 2017 13:59 #
Hi Marco, I also do not know of a built-in way to do this, but here is my shot at an implementation in XQuery. It uses fast exponentiation [1] and throws a custom error if there is more than one "e" in the input. Hope that helps (or is of interest), I had fun hacking it together, Leo
    declare function local:pow($n, $k) {
      if($k eq 0) then xs:decimal('1')
      else if($k eq 1) then $n
      else (
        let $d := $k idiv 2,
            $m := $k mod 2
        return if($m eq 0) then local:pow($n * $n, $d)
        else local:pow($n * $n, $d) * $n
      )
    };

    declare function local:parse-decimal($str as xs:string) as xs:decimal {
      let $parts := tokenize($str, '[eE]')
      return switch(count($parts))
        case 1 return xs:decimal($str)
        case 2 return (
          let $exp  := xs:long($parts[2]),
              $base := xs:decimal($parts[1]),
              $b10  := if($exp gt 0) then xs:decimal('10') else xs:decimal('0.1')
          return $base * local:pow($b10, $exp)
        )
        default return error(xs:QName('local:NODECIML'), 'Wrong format: ' || $str)
    };

    local:parse-decimal('123.45e-300')
Quoted text · Marco Lettere · 28 lines
Am Mittwoch, 01. November 2017 13:21 CET, Marco Lettere <m.lettere at gmail.com> schrieb: > Thanks Kristian, > unfortunately this introduces rounding errors which I'm trying to avoid > because managing units, measures and monetary amounts. > M. > > Il 01 nov 2017 12:57 PM, "Kristian Kankainen" <kristian at keeleleek.ee> ha > scritto: > > You need to use xs:float or xs:double instead of xs:decimal to be able to > use the 'e' or 'E' as the exponent separator. > > Br, > Kristian K1. nov 2017 13:18 kirjutas kuupäeval Marco Lettere < > m.lettere at gmail.com>: > > > > Hi all, > > > > I thought of asking this in parallel of hacking my own parsing procedure > > ... > > > > Is there a native way to parse scientific notation string into > > xs:decimal since a direct casting (xs:decimal("1e1")) is not allowed? > > > > Thanks, > > > > Marco. > >
ML
Marco Lettere1 Nov 2017 15:14 #
Awesome Leo, thanks! Similar to what I was thinking about but with a lot or after-thought optimization! Great suggestion. M.
Quoted text · Leonard Wörteler · 73 lines
Il 01 nov 2017 1:59 PM, "Leonard Wörteler" < leonard.woerteler at uni-konstanz.de> ha scritto: > Hi Marco, > > I also do not know of a built-in way to do this, but here is my shot at an > implementation in XQuery. It uses fast exponentiation [1] and throws a > custom error if there is more than one "e" in the input. > > Hope that helps (or is of interest), I had fun hacking it together, > Leo > > declare function local:pow($n, $k) { > if($k eq 0) then xs:decimal('1') > else if($k eq 1) then $n > else ( > let $d := $k idiv 2, > $m := $k mod 2 > return if($m eq 0) then local:pow($n * $n, $d) > else local:pow($n * $n, $d) * $n > ) > }; > > declare function local:parse-decimal($str as xs:string) as xs:decimal { > let $parts := tokenize($str, '[eE]') > return switch(count($parts)) > case 1 return xs:decimal($str) > case 2 return ( > let $exp := xs:long($parts[2]), > $base := xs:decimal($parts[1]), > $b10 := if($exp gt 0) then xs:decimal('10') else > xs:decimal('0.1') > return $base * local:pow($b10, $exp) > ) > default return error(xs:QName('local:NODECIML'), 'Wrong format: ' > || $str) > }; > > local:parse-decimal('123.45e-300') > > [1] https://en.wikipedia.org/wiki/Exponentiation_by_squaring > > Am Mittwoch, 01. November 2017 13:21 CET, Marco Lettere < > m.lettere at gmail.com> schrieb: > > Thanks Kristian, > > unfortunately this introduces rounding errors which I'm trying to avoid > > because managing units, measures and monetary amounts. > > M. > > > > Il 01 nov 2017 12:57 PM, "Kristian Kankainen" <kristian at keeleleek.ee> ha > > scritto: > > > > You need to use xs:float or xs:double instead of xs:decimal to be able to > > use the 'e' or 'E' as the exponent separator. > > > > Br, > > Kristian K1. nov 2017 13:18 kirjutas kuupäeval Marco Lettere < > > m.lettere at gmail.com>: > > > > > > Hi all, > > > > > > I thought of asking this in parallel of hacking my own parsing > procedure > > > ... > > > > > > Is there a native way to parse scientific notation string into > > > xs:decimal since a direct casting (xs:decimal("1e1")) is not allowed? > > > > > > Thanks, > > > > > > Marco. > > > > >

⚡Generated with XQuery