Chicken pot pie... This was our Easter dinner, mostly made by me but with a spicing assist from Debbie. We've made this recipe several times before, and we've experimented with some modifications. This time we added mushrooms and celery, used rotisserie chicken (from Macey's) instead of sauteed chicken, fresh carrots instead of frozen, and frozen peas and corn instead of mixed veggies. We kept throwing everything that sounded good to us into the pot. :) Then Debbie got going on the spices, and as far as I could tell she dumped about 30 kinds of spices into the mix, all in enormous quantities. I have no idea what they were. Seriously. So the chance of accurate replication is pretty small.
These deviations from the recipe had another result as well: we ended up with twice as much filling as we were supposed to. I ended up vacuum-bagging (for freezing) half the filling, and baking the rest with the puff pastry top. When it was done, we tucked into it with enthusiasm and managed to put away about 1/3 of that pan. Debbie actually had more than I did! I took about half the rest and put it in a refrigerator container. The remainder is now in two more vacuum-bags, waiting to cool down before I vacuum them and toss them in the freezer. We have much (yummy!) chicken pot pie in our future!
While I was cooking this, I had to add quite a bit of broth and cream to get enough liquid (because we added so much good stuff). The sauce is thickened with a roux, and I hadn't changed that from the recipe. That meant the sauce was way too thin, so I whipped up some more butter-and-flour roux in a little frying pan. That worked great – when I threw that roux in, the sauce thickened right up. I like the flavor and texture of a roux way better than cornstarch, so I was glad I did it that way...
Sunday, April 16, 2017
How about scaled integers for monetary amounts?
How about scaled integers for monetary amounts? A friend recently wondered why I wouldn't simply use scaled integers for monetary amounts. For instance, if I determined that all I needed was 10 significant integer digits, plus 4 decimal places, then I could exactly represent any decimal value within that range by multiplying it times 10,000 and using the resulting integer. For example, I could represent 382.03 as 3,820,300. When it came time to present that number to a human, I'd just divide by 10,000.
Scaled integers work particularly well for addition and subtraction, and for many financial applications that's the bulk of what they do. Consider this addition example, unscaled on the left and scaled by 10,000 on the right:
Multiplies aren't quite as lovely, though. The scale factor gets multiplied along with the actual number, so you get a result that has to be divided by the scale factor to get a correctly scaled result. Example:
And then there's division, where the scale factor essentially is canceled out – requiring you to multiply the result by the scale factor to re-scale it.
If these numbers at our desired precision all fit into a native integer type, this would be a bit unwieldy, a little less performant than native, but workable. In an earlier post I figured that we needed a range that encompassed at least 30 decimal digits just to represent amounts of money. The binary equivalent of 30 decimal digits is about 100 bits. The largest native integer in Java (the long) has 63 significant bits – not even close.
Well, what if we used two longs? That would give us 126 significant bits – plenty of room. Addition and subtraction are still simple with this scheme. Multiplication is a bit harder, but still workable. Division is a bear, though, and substantially slower than a native implementation. Those aren't necessarily deal-killers, just a consideration. A similar issue arises from the fact that with this scheme it takes 16 bytes to store any number. That's expensive in database, mass storage, network transmission, and CPU cache (for any application that uses lots of values, i.e. most of them). But still not necessarily a deal killer.
But, as my mother-in-law would say, there's a worser problem with scaled integers. It derives from the fact that you don't just represent monetary values in an application – you also do math with them. I've used the simple example of multiplying price times quantity to get extended price, but many financial applications do much more than such simple math.
Just to pick one example out of my checkered past: I once was charged with building applications that modeled the performance of complex bonds (that is, those with fancy terms in them, not just simple interest), over wide ranges of multiple environmental variables (LIBOR rate, inflation rate, etc.) in combination with each other. These models had multi-dimensional tables with millions of entries, each of which contained a calculated probable value. In some of the models I built, these values could be as small as 10^-10, with around 8 significant digits. That's not something exotic and unusual, either – it's a perfectly normal sort of financial application.
Here's the real point, though: financial applications need to do math with money, and we really can't predict what the range of numbers they'll need will be. This point has been driven home for me by a number of bad experiences out in that pesky real world. Every application I've ever worked on that used fixed point numeric representation (which scaled integers are an example of) has run into problems with the range of numbers they could represent. The failure modes can be very bad, too – especially if the fixed point implementations aren't good at catching overflows (and many of them don't even try, because of the performance penalty).
This hard stop on the range of numeric values held is the real deal-killer for me with fixed point representations. The performance and size issues just make it a little bit worse. In my opinion, fixed point representation and manipulation of monetary values is a dangerous source of fragility in financial applications. Further, it's one that is very difficult to repair – once the decision to use a particular fixed point representation is made, that decision creates tendrils of dependency that find their way into every nook and cranny of the application.
So how do you avoid this? There's a good solution, but it comes with its own costs: decimal floating point. That will be the subject of a few more posts...
Scaled integers work particularly well for addition and subtraction, and for many financial applications that's the bulk of what they do. Consider this addition example, unscaled on the left and scaled by 10,000 on the right:
773.32 7733200
27.99 279900
------ -------
801.31 8013100
Multiplies aren't quite as lovely, though. The scale factor gets multiplied along with the actual number, so you get a result that has to be divided by the scale factor to get a correctly scaled result. Example:
4.45 44500
6.02 60200
------ ----------
26.789 2678900000 rescaled to
267890
And then there's division, where the scale factor essentially is canceled out – requiring you to multiply the result by the scale factor to re-scale it.
773.32 7733200
27.99 279900
------ -------
27.63 27.63 rescaled to 276300 (results are rounded)
If these numbers at our desired precision all fit into a native integer type, this would be a bit unwieldy, a little less performant than native, but workable. In an earlier post I figured that we needed a range that encompassed at least 30 decimal digits just to represent amounts of money. The binary equivalent of 30 decimal digits is about 100 bits. The largest native integer in Java (the long) has 63 significant bits – not even close.
Well, what if we used two longs? That would give us 126 significant bits – plenty of room. Addition and subtraction are still simple with this scheme. Multiplication is a bit harder, but still workable. Division is a bear, though, and substantially slower than a native implementation. Those aren't necessarily deal-killers, just a consideration. A similar issue arises from the fact that with this scheme it takes 16 bytes to store any number. That's expensive in database, mass storage, network transmission, and CPU cache (for any application that uses lots of values, i.e. most of them). But still not necessarily a deal killer.
But, as my mother-in-law would say, there's a worser problem with scaled integers. It derives from the fact that you don't just represent monetary values in an application – you also do math with them. I've used the simple example of multiplying price times quantity to get extended price, but many financial applications do much more than such simple math.
Just to pick one example out of my checkered past: I once was charged with building applications that modeled the performance of complex bonds (that is, those with fancy terms in them, not just simple interest), over wide ranges of multiple environmental variables (LIBOR rate, inflation rate, etc.) in combination with each other. These models had multi-dimensional tables with millions of entries, each of which contained a calculated probable value. In some of the models I built, these values could be as small as 10^-10, with around 8 significant digits. That's not something exotic and unusual, either – it's a perfectly normal sort of financial application.
Here's the real point, though: financial applications need to do math with money, and we really can't predict what the range of numbers they'll need will be. This point has been driven home for me by a number of bad experiences out in that pesky real world. Every application I've ever worked on that used fixed point numeric representation (which scaled integers are an example of) has run into problems with the range of numbers they could represent. The failure modes can be very bad, too – especially if the fixed point implementations aren't good at catching overflows (and many of them don't even try, because of the performance penalty).
This hard stop on the range of numeric values held is the real deal-killer for me with fixed point representations. The performance and size issues just make it a little bit worse. In my opinion, fixed point representation and manipulation of monetary values is a dangerous source of fragility in financial applications. Further, it's one that is very difficult to repair – once the decision to use a particular fixed point representation is made, that decision creates tendrils of dependency that find their way into every nook and cranny of the application.
So how do you avoid this? There's a good solution, but it comes with its own costs: decimal floating point. That will be the subject of a few more posts...
Paradise ponders, recoveries, flowers, stairs, and risers edition...
Paradise ponders, recoveries, flowers, stairs, and risers edition... Debbie had a milestone day yesterday for her post-surgery recovery. Her bandages came off in the morning (she couldn't do it – got queasy – so I did it for her :). Then she took a shower; oh, so good. Then she got down the stairs to our basement cattery to see her babies. Then we had a steak dinner. Then we went up to Aggie's Creamery and got ice cream cones. A great day for her! But she was tired for some reason after all that. :)
We've got a few flowers in our yard. The daffodils have started to bloom, and then the ground cover (at right) we have in several places is also out. After all the destruction of our yard last year (and continuing this year), I'm amazed anything at all has survived. The sweet peas are starting to come up, too – probably another two or three weeks and they'll be a big burst of color to the west of our house...
Yesterday I completed the installation of the stairs I built into our sun room (photos below). All my careful measuring paid off: the stairs fit perfectly on the first try. The landing is level with our bedroom floor, as intended, and the little “lip” I machined out fit over the door sill exactly as intended. I'm very pleased with the way the finish blends with our tile floor, too. Next step: some more careful measurements for the rail (it will be on the left side). Once I make those, I'll send them off to the folks at Lazy K Wrought Iron to get a rail made. At that point our sun room will (finally!) be complete. We'll make another road trip up there to get them!
Mark T., Dave, and Dave's three sons were here all day yesterday installing 6" diameter irrigation pipe to move the line of risers that used to be in the middle of our back yard to just outside the fence. The new line of risers (visible if you embiggen the photo at right) is a couple of feet onto the property of our friend and neighbor Tim D. Once my sprinklers are installed (that's the next thing Mark T. will be working on), I won't need them at all – but Tim will, to irrigate the 2.5 acre field to the left (north) in the photo. It's a big chunk of work to move all that, and Mark and his helpers did a really nice job of it. The only bit they have left is the easy part: gluing the risers in place onto those vertical 3" pipes. Then it's on to the sprinklers in our yard!
We've got a few flowers in our yard. The daffodils have started to bloom, and then the ground cover (at right) we have in several places is also out. After all the destruction of our yard last year (and continuing this year), I'm amazed anything at all has survived. The sweet peas are starting to come up, too – probably another two or three weeks and they'll be a big burst of color to the west of our house...
Yesterday I completed the installation of the stairs I built into our sun room (photos below). All my careful measuring paid off: the stairs fit perfectly on the first try. The landing is level with our bedroom floor, as intended, and the little “lip” I machined out fit over the door sill exactly as intended. I'm very pleased with the way the finish blends with our tile floor, too. Next step: some more careful measurements for the rail (it will be on the left side). Once I make those, I'll send them off to the folks at Lazy K Wrought Iron to get a rail made. At that point our sun room will (finally!) be complete. We'll make another road trip up there to get them!
Mark T., Dave, and Dave's three sons were here all day yesterday installing 6" diameter irrigation pipe to move the line of risers that used to be in the middle of our back yard to just outside the fence. The new line of risers (visible if you embiggen the photo at right) is a couple of feet onto the property of our friend and neighbor Tim D. Once my sprinklers are installed (that's the next thing Mark T. will be working on), I won't need them at all – but Tim will, to irrigate the 2.5 acre field to the left (north) in the photo. It's a big chunk of work to move all that, and Mark and his helpers did a really nice job of it. The only bit they have left is the easy part: gluing the risers in place onto those vertical 3" pipes. Then it's on to the sprinklers in our yard!