Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: How to avoid an overflow during multiplication? Date: Fri, 31 Dec 2021 17:39:59 -0800 Organization: A noiseless patient Spider Lines: 67 Message-ID: <864k6oz11s.fsf@linuxsc.com> References: <86a6ggzl16.fsf@linuxsc.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="8d4c26aa7c7194cacc690ff896698f96"; logging-data="25193"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18hxPgUOsmxQkBeJwi55RvlpNl8Ut/nGzQ=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:DdMz21Kf3Vsk9HomCNTlReRsYV0= sha1:VBtLAbIJ8xq54WEnBuFKpNezgoA= Xref: csiph.com comp.lang.c:164189 Mateusz Viste writes: > 2021-12-31 at 10:28 -0800, Tim Rentsch wrote: > >> Next you might not know the identity >> >> a*b/c === a*(b/c) + a*(b%c)/c >> >> Of course multiplication is commutative, so we can also write: >> >> a*b/c === b*(a/c) + b*(a%c)/c > > Hello Tim, > > Thank you for the extensive explanations. What you suggest has already > been proposed by Michael S. earlier today [...] What can I say, great minds think alike. :) > I tested it, and it does work very well. > >> uint32_t ticks2time_2( uint32_t ticks, uint32_t scale ) { >> return ticks*tempo_scale_q + ticks*tempo_scale_r/scale; >> } >> >> which probably will be faster than the original. > > The pre-computation subject has been also mentioned already, but thank > you nonetheless for the nice and self-explanatory example code, that's > very kind of you. I try to give lucid explanations. I appreciate you appreciating them. > As for being faster than the original - I really doubt it. > The original was this: > > return ticks * (tempo / scale); > > ie. one division followed by one multiplication. [...] Oh, by original I meant my own earlier version: uint32_t ticks2time( uint32_t ticks, uint32_t scale, uint16_t tempo ){ return ticks*(tempo/scale) + ticks*(tempo%scale)/scale; } in which case I expect the precompute version will indeed be faster. One further idea.. after posting it occurred to me that there is a technique that is guaranteed to give the right answer as long as the result fits in 32 bits: uint32_t ticks2time( uint32_t ticks, uint16_t tempo, uint16_t scale ){ uint32_t th = ticks >> 16; uint32_t th_tempo = th * tempo; uint32_t tl = (uint16_t) ticks; return (th_tempo / scale << 16) + ((th_tempo % scale << 16) + tl*tempo) / scale; } This approach is of course more expensive to compute, but it might be worth trying, as a sanity check if nothing else.