6 ms·
Sadly the lack of a decimal type complicates monetary calculations sufficiently for me to stay with postgresql even for small projects that could easily be done
by fauigerzigerk 9y ago
Sadly the lack of a decimal type complicates monetary calculations sufficiently for me to stay with postgresql even for small projects that could easily be done with SQLite.
- BenjiWiebe 9y agoWhy wouldn't you just store the value in cents? And divide by 100 to display it.
- fauigerzigerk 9y agoAs I said in my reply to asaph, it doesn't work well with interest rates and exchange rates. Also, it simply adds to the mental load in many places (e.g ad hoc queries)
- TeMPOraL 9y agoAnd floats do? With all the (implicit) rounding and precision issues, and some base-10 numbers not being representable in an exact form? Serious question, what's the proper way to handle this case? I'm having hard time to believing it's IEEE-754 floats.
- fauigerzigerk 9y agoNo, binary floating point doesn't work at all. Decimal floating point can work if the representation is large enough.
- icebraining 9y agoArbitrary-precision numbers. DBs like Postgres support them, as do most languages (e.g. Ruby has BigDecimal, Python has Decimal).
- aeorgnoieang 9y agoNeither `BigDecimal` in Ruby or `Decimal` in Python are quite what I'd expect for "arbitrary-precision". From the docs for [`BigDecimal`](http://ruby-doc.org/stdlib-1.9.3/libdoc/bigdecimal/rdoc/BigDecimal.html http://ruby-doc.org/stdlib-1.9.3/libdoc/bigdecimal/rdoc/BigD...): > Ruby provides built-in support for arbitrary precision integer arithmetic. For example: > > 4213 -> 1265437718438866624512 > > BigDecimal provides similar support for very large or very accurate floating point numbers. My takeaway from the above is that, if arbitrary precision is needed, you should still just use integers. Tho, in practice, it may not be significant.
- fauigerzigerk 9y agoIntegers are not magic. If you want arbitrary precision on top of integers you're going to need arbitrarily long integers as well.
- aeorgnoieang 9y agoI was referring to Ruby and based on the first sentence I quoted: > Ruby provides built-in support for arbitrary precision integer arithmetic. [I'm also assuming that it's really arbitrary precision and not just 'really big but limited' precision.]
- elteto 9y agoOP mentioned a decimal data type, which in postgres can have a very large precision: https://www.postgresql.org/docs/10/static/datatype-numeric.html https://www.postgresql.org/docs/10/static/datatype-numeric.h.... Not the same as a floating point.
- anarazel 9y ago16383 digits ought to be enough for everyone: "up to 131072 digits before the decimal point; up to 16383 digits after the decimal point" Non jokingly: I think precision wise that's really plenty enough for pretty much any halfway realistic usecase (no, don't do public key crypto using SQL datatypes). There's some issues with the numeric / decimal type, but lack of potential precision isn't one of them.
- aldanor 9y agoThe proper way to handle this is fixed-point representation (whether the DB natively supports this or not). E.g., you won't find floating point fields in binary protocols for any of the major stock exchanges. A typical scaling factor is 10^8, so if the exchange wants to tell you that the price is now 101.27, they send you an int64 value of 10127000000. You may then choose to take it further and store e.g. in 128-bit decimal. Of course, there's an issue of how to handle mul/div (i.e., rounding/truncation), but that's a separate question -- at least you'd be making decisions yourself rather than relying on how IEEE-754 floats work. Some DBs like PG, do, as a matter of fact, support decimals natively which makes things quite a bit simpler.
- KMag 9y agoCertainly for decimalized exchanges, binary floating point is the wrong choice. (On a side note, it's also the wrong choice for spread sheets, at least as the default. The average freshly graduated accountant can have a reasonable grasp on decimal floating point rounding after a 5 minute explanation, whereas most professional software engineers with a decade of experience have a very weak understanding of IEEE 754 binary floating point.) > E.g., you won't find floating point fields in binary protocols for any of the major stock exchanges. That's true of NASDAQ's OUCH, but some (many?) other protocols use decimal floating point. NYSE's UTP Direct[0] (See section 4.15) Is not fixed point, but actually their own decimal floating point system with a 32-bit significand and single ASCII character exponent ("0" to "6", indicating negated base 10 exponent, not allowing "5"). FIX SBE uses an 8 byte significand and a 1 byte (power-of-10) exponent, if I remember correctly. It's a bit unfortunate that (as far as I know) there aren't any major messaging formats supporting IEEE 754-2008 decimal64 values. [0]https://www.nyse.com/publicdocs/nyse/markets/nyse/NYSEUTPDirect_Specification.pdf https://www.nyse.com/publicdocs/nyse/markets/nyse/NYSEUTPDir...
- dragonwriter 9y agoSerious monetary work often needs values smaller than cents. Exact decimals or, better, exact fractions are often what you want.
- lsaferite 9y agoWhat is the typical use-case of a unit smaller than the smallest tradable currency unit? Mind you, I understand there are smaller units than the circulated currency (For the USD you have a mill which is 1/10 of a cent).
- tracker1 9y agoBitcoin currency trades? Large fractions. Convert to/from yuan/yen, large whole numbers, back to US, somewhere in the middle. Tracking transactional values for large stock and currency trades would be an example. That said, could use integers to represent arbitrary precision.
- asaph 9y agoStore your monetary values as cents instead of dollars and use integers. Convert to dollars in the presentation layer. My assumption here is that you're dealing in US currency but the same idea applies to any currency; use integers, not decimals.
- fauigerzigerk 9y agoSay you have a savings account with an interest rate of 0.125% and any interest has to be converted into another currency for taxation purposes at a rate of 0.88619. Working around these sorts of problems with integers is just not worth the trouble.
- haimez 9y agoYes it is. You convert to a big decimal representation, compute the tax/interest and then intentionally round back to an integer format using the appropriate rounding mode.
- ifdefdebug 9y agoGP didn't say it's impossible, he said it's not worth the trouble which is an opinion statement that can't be countered with "yes it is".
- haimez 9y agoYes, it can. The case and point is that you need to control where those moments of imprecision happen, and using fixed point a fixed point (often integer/long) representation is absolutely worth the effort because it's not much effort at all and you DEFINITELY care about when your money calculations involved rounding.
- fauigerzigerk 9y agoAnd why would I not prefer to get help from a database system to do that?
- hajile 9y agoThe computer has only integers and floats for purposes of calculation (except for some IBM units implementing IEEE fixed point). In storage though, there are only whole numbers to which we assign meaning. Store your as a single integer then write a small layer that converts that integer into decimal (that's all a language or DB does anyway). Alternatively, use two entries in the database for each side of the decimal if you want even more precision or store it as a string if you want arbitrary precision.
- fauigerzigerk 9y ago>(that's all a language or DB does anyway) Well, that's my point. Postgres does it for me. SQLite doesn't. I'm lazy. Also, SQLite's largest integer type is 64 bits. That's awfully tight for some use cases.
- cdelsolar 9y agoimport decimal; decimal.Decimal('3.14159')
- fauigerzigerk 9y agoA few words of explanation wouldn't hurt. Are you saying that I shouldn't ever do monetary calculations in the database at all? If so then I have to disagree.
- sigzero 9y agoNo, they are giving ways to do it outside of the db. You really answered your own bias on this. You want the db to handle it, so you wouldn't use sqlite in the first place.
- prewett 9y agoI'm curious how 64-bits would be tight for monetary data. A 64-bit integer is +/- 9e18, which is so big I don't even know how to actually say that number. Given that economies are only in the trillions, you have at least three orders of magnitude left when representing the largest amounts of money on the planet. Anything smaller would be a piece of cake. Also, seems like the obvious thing to do to store money in an integer would be to store it in pennies. Or if the numbers get too big, do what corporate financial reports do and use thousands.
- dragonwriter 9y agoYou could just store decimal strings and use application-language decimal functions to operate on them, even in queries, since it's fairly trivial to use application-language functions as SQLite (scalar or aggregate) database functions, at least in most decent SQLite drivers I've seen. It's one of the advantages of an in-process database.
- fauigerzigerk 9y agoInteresting. I'll look into it next time it comes up. I wonder how it interacts with indexes and how it affects performance generally.
- BareNakedCoder 9y agoStrings don't work well with numeric aggregate SQL functions like SUM or MAX. Also, won't work well with comparisons or sorting: "111.00" is less than "9.99" string-wise (unless you store all numerics with a bunch of leading "0"; but then that takes a lot more space).
- tracker1 9y agoCould look at Firebird if you want something embedded still. Can even scale to use a server mode. I wrote a distributed system about a decade and a half ago using Firebird, worked pretty well.