Path: ...!weretis.net!feeder6.news.weretis.net!feeder8.news.weretis.net!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Bart Newsgroups: comp.lang.c Subject: Re: Can this program be improved? Date: Thu, 30 Dec 2021 01:06:23 +0000 Organization: A noiseless patient Spider Lines: 80 Message-ID: References: <87sfub2g2t.fsf@nosuchdomain.example.com> <87o84z2bsi.fsf@nosuchdomain.example.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Thu, 30 Dec 2021 01:06:23 -0000 (UTC) Injection-Info: reader02.eternal-september.org; posting-host="50a6f6e5a951aff34d7b2de53679ba6e"; logging-data="5218"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+X/dOwOZCsd8d8B54INRT69/2h1dgddCc=" User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Thunderbird/91.4.1 Cancel-Lock: sha1:P2pxfvSBo5Vt3KdY5CkVIoDOO+k= In-Reply-To: <87o84z2bsi.fsf@nosuchdomain.example.com> Bytes: 4998 On 30/12/2021 00:09, Keith Thompson wrote: > Bart writes: >> Real-world doesn't need to mean dealing with trillions of dollars to >> the exact cent. > > But it can mean dealing with thousands of dollars to the exact cent -- > and if you get a result of $1234.565001 and round it to $1234.57, when > the rules call for a result of $1234.56, that could be a serious problem. With floating point, that result could as easily be just under 1234.565 as just over. If the requirements really are that binary floating point must have exactly identical results, down to the least significant bit, even for intermediates so that rounding will always give the same results too, then that's what you have to do. But I don't believe the OP's program is in that class. (This is one of a category of exercises, like hashes, prngs, and reading a line of input of arbitrary length, where apparently nothing less that a perfect, industrial-strength professional solution will do.) >> Most businesses work with amounts far smaller. Then I believe the >> precision of float64 is enough to emulate the needed rounding methods. > > Working with smaller amounts just means that errors like this are rarer, > not that they don't happen. > >> (But I didn't even bother with that. My app anyway had to work with >> multliple parallel currencies so if an amount was correct to the >> nearest cent on one, it couldn't also be correct in another. But the >> environment was also fairly informal.) > > If "fairly informal" means you don't need results accurate to the cent, > then floating-point might be good enough. But financial institutions > can't afford that. You can easily get results to the nearest cent. The problem can be when rounding errors or rounding methods result in discrepancies between different approaches, or between different programs and languages. I just don't think this is a programming issue, more one of requirements and specification. >> I wouldn't know where to start to apply an interest rate specified to >> multiple decimals, to an integer amount, to yield an integer result. > > Neither would I. My understanding is that there are precisely stated > rules that tell you exactly what results a given computation must > produce, for example when computing compound interest. If you're going > to be writing real-world software, where satisfying those rules is a > requirement, you *must* learn those rules first. (I haven't done so and > probably won't.) Again with real-world. Is this a corner shop or is it Lloyds Bank? Or someone working out figures for their tax return? Or doing a personal budget? (In my country, tax returns only need figures in whole pounds, and don't need to be that exact. So long as you are not deliberately misrepresenting by significant amounts, it doesn't matter if they are a pound either way.) So, what do you think the OP should do? Remember this is floating point which is generally not exact: 1.00625 (the factor needed for 7.5% annual interest applied monthly) can't be represented precisely IEEE754. Using long integers for this isn't a magic bullet, since you still have to multiply by 1.00625. As it turns out, I do have a clue how it's done: you multiply by 100625 and divide by 100000. However, int64 or even int128 don't have enough range to multiply by 100625 N times before dividing by 100000 N times. You have to do the divide at each step. Which means deciding what to do about the remainder at each step (especially if negative numbers are involved). It's back to specifications.