Rocksolid Light

Welcome to novaBBS (click a section below)

mail  files  register  newsreader  groups  login

Message-ID:  

24 Apr, 2024: Testing a new version of the Overboard here. If you have an issue post about it to rocksolid.nodes.help (I know. Everyone on Usenet has issues)


devel / comp.lang.c / How to avoid an overflow during multiplication?

SubjectAuthor
* How to avoid an overflow during multiplication?Mateusz Viste
+* Re: How to avoid an overflow during multiplication?Stefan Ram
|`- Re: How to avoid an overflow during multiplication?Ben Bacarisse
+* Re: How to avoid an overflow during multiplication?Ben Bacarisse
|`* Re: How to avoid an overflow during multiplication?Mateusz Viste
| +* Re: How to avoid an overflow during multiplication?Stefan Ram
| |+* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||`* Re: How to avoid an overflow during multiplication?Keith Thompson
| || `* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  +* Re: How to avoid an overflow during multiplication?James Kuyper
| ||  |`* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  | `* Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |  `* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   +* Re: How to avoid an overflow during multiplication?David Brown
| ||  |   |`* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   | +- Re: How to avoid an overflow during multiplication?James Kuyper
| ||  |   | `* Re: How to avoid an overflow during multiplication?David Brown
| ||  |   |  `* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   |   `* Re: How to avoid an overflow during multiplication?David Brown
| ||  |   |    `* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   |     `* Re: How to avoid an overflow during multiplication?David Brown
| ||  |   |      `* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   |       `* Re: How to avoid an overflow during multiplication?Richard Damon
| ||  |   |        +* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   |        |`* Re: How to avoid an overflow during multiplication?David Brown
| ||  |   |        | `* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   |        |  `- Re: How to avoid an overflow during multiplication?David Brown
| ||  |   |        `* Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   |         `* Re: How to avoid an overflow during multiplication?David Brown
| ||  |   |          `* Re: How to avoid an overflow during multiplication?Bart
| ||  |   |           `* Re: How to avoid an overflow during multiplication?Öö Tiib
| ||  |   |            +- Re: How to avoid an overflow during multiplication?Bart
| ||  |   |            `- Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   +* Re: How to avoid an overflow during multiplication?James Kuyper
| ||  |   |`* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   | `- Re: How to avoid an overflow during multiplication?James Kuyper
| ||  |   +* Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |`* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   | `* Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |  `* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   |   +* Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |   |`* Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   |   | `* Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |   |  `* Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   |   |   `* Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |   |    +* Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |   |    |`* Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   |   |    | `* Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |   |    |  +* Re: How to avoid an overflow during multiplication?Keith Thompson
| ||  |   |   |    |  |`* Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |   |    |  | +* Re: How to avoid an overflow during multiplication?Ben Bacarisse
| ||  |   |   |    |  | |`- Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |   |    |  | `* Re: How to avoid an overflow during multiplication?Keith Thompson
| ||  |   |   |    |  |  `- Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |   |    |  `- Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   |   |    `* Re: How to avoid an overflow during multiplication?James Kuyper
| ||  |   |   |     `* Re: How to avoid an overflow during multiplication?Manfred
| ||  |   |   |      `* Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |   |   |       `- Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   |   `- Re: How to avoid an overflow during multiplication?Ben Bacarisse
| ||  |   +* Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   |`* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |   | +- Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   | `* Re: How to avoid an overflow during multiplication?James Kuyper
| ||  |   |  `- Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   +- Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |   `* Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |    `* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |     `* Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |      `* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |       +* Re: How to avoid an overflow during multiplication?Keith Thompson
| ||  |       |`- Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |       +* Re: How to avoid an overflow during multiplication?Vir Campestris
| ||  |       |`* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |       | +* Re: How to avoid an overflow during multiplication?James Kuyper
| ||  |       | |+* Re: How to avoid an overflow during multiplication?Öö Tiib
| ||  |       | ||`* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |       | || +- Re: How to avoid an overflow during multiplication?Öö Tiib
| ||  |       | || `* Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |       | ||  `* Re: How to avoid an overflow during multiplication?Bart
| ||  |       | ||   +* Re: How to avoid an overflow during multiplication?Ben Bacarisse
| ||  |       | ||   |`- Re: How to avoid an overflow during multiplication?Bart
| ||  |       | ||   `- Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  |       | |`* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |       | | +* Re: How to avoid an overflow during multiplication?David Brown
| ||  |       | | |+* Re: How to avoid an overflow during multiplication?Malcolm McLean
| ||  |       | | ||`* Re: How to avoid an overflow during multiplication?David Brown
| ||  |       | | || `* Re: How to avoid an overflow during multiplication?Mateusz Viste
| ||  |       | | ||  `* Re: How to avoid an overflow during multiplication?David Brown
| ||  |       | | ||   `- Re: How to avoid an overflow during multiplication?Malcolm McLean
| ||  |       | | |`* Re: How to avoid an overflow during multiplication?Bart
| ||  |       | | | +* Re: How to avoid an overflow during multiplication?David Brown
| ||  |       | | | |`* Re: How to avoid an overflow during multiplication?Bart
| ||  |       | | | | +* Re: How to avoid an overflow during multiplication?David Brown
| ||  |       | | | | |+* Re: How to avoid an overflow during multiplication?Bart
| ||  |       | | | | ||`* Re: How to avoid an overflow during multiplication?David Brown
| ||  |       | | | | || `- Re: How to avoid an overflow during multiplication?Bart
| ||  |       | | | | |`* Re: How to avoid an overflow during multiplication?Manfred
| ||  |       | | | | | +* Re: How to avoid an overflow during multiplication?James Kuyper
| ||  |       | | | | | |`- Re: How to avoid an overflow during multiplication?Manfred
| ||  |       | | | | | `- Re: How to avoid an overflow during multiplication?David Brown
| ||  |       | | | | `* Re: How to avoid an overflow during multiplication?james...@alumni.caltech.edu
| ||  |       | | | `* Re: How to avoid an overflow during multiplication?james...@alumni.caltech.edu
| ||  |       | | `* Re: How to avoid an overflow during multiplication?James Kuyper
| ||  |       | +- Re: How to avoid an overflow during multiplication?Scott Lurndal
| ||  |       | `* Re: How to avoid an overflow during multiplication?Vir Campestris
| ||  |       +- Re: How to avoid an overflow during multiplication?James Kuyper
| ||  |       `* Re: How to avoid an overflow during multiplication?Tim Rentsch
| ||  `- Re: How to avoid an overflow during multiplication?Keith Thompson
| |`- Re: How to avoid an overflow during multiplication?Guillaume
| `* Re: How to avoid an overflow during multiplication?David Brown
+* Re: How to avoid an overflow during multiplication?Bonita Montero
+* Re: How to avoid an overflow during multiplication?Michael S
+* Re: How to avoid an overflow during multiplication?Kaz Kylheku
+* Re: How to avoid an overflow during multiplication?Tim Rentsch
`* Re: How to avoid an overflow during multiplication?Stefan Ram

Pages:12345678
How to avoid an overflow during multiplication?

<sqmkg9$157v$1@gioia.aioe.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19708&group=comp.lang.c#19708

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!aioe.org!299gYy2nqWB43X4cCBV6zg.user.46.165.242.75.POSTED!not-for-mail
From: mate...@xyz.invalid (Mateusz Viste)
Newsgroups: comp.lang.c
Subject: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 11:02:49 +0100
Organization: . . .
Message-ID: <sqmkg9$157v$1@gioia.aioe.org>
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="38143"; posting-host="299gYy2nqWB43X4cCBV6zg.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
X-Notice: Filtered by postfilter v. 0.9.2
 by: Mateusz Viste - Fri, 31 Dec 2021 10:02 UTC

I have this little function:

/* converts an amount of ticks into human time (micro-seconds)
* timeunits: number of ticks to convert into actual time
* tempo : the time length (in microseconds) of grouplen ticks
*/
uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t tempo)
{ return ticks * tempo / grouplen;
}

In practical situations the end result of this computation is
guaranteed to always fit inside an uint32_t, but the above formula
overflows easily in the (ticks * tempo) part.

The easy & stupid way to avoid this overflow would be this:

return ticks * (tempo / grouplen);

....but it's obviously not a good solution, since it may loose a lot of
resolution. The hacky compromise that I currently use is this:

return ticks * (((tempo << 3) / grouplen) >> 3);

It works fine in my practical tests, so I might just as well be done
with it, but I wonder if there is a cleaner approach to such seemingly
simple problem?

I should also add that this part of the program is performance
critical, so I cannot afford branching or any other expensive
computations. It's also worth noting that "grouplen" is guaranteed to
be a positive number that never changes across the calls of the
function (which, in truth, is not even a function, but it was easier to
format it as such for this exercise).

Mateusz

Re: How to avoid an overflow during multiplication?

<multiplication-20211231130316@ram.dialup.fu-berlin.de>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19709&group=comp.lang.c#19709

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: ram...@zedat.fu-berlin.de (Stefan Ram)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: 31 Dec 2021 12:04:08 GMT
Organization: Stefan Ram
Lines: 18
Expires: 1 Apr 2022 11:59:58 GMT
Message-ID: <multiplication-20211231130316@ram.dialup.fu-berlin.de>
References: <sqmkg9$157v$1@gioia.aioe.org>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Trace: news.uni-berlin.de sROoMYNA1yY8QD/r1heQmwn5eaKMCbetfm4y7vMc2gGdJh
X-Copyright: (C) Copyright 2021 Stefan Ram. All rights reserved.
Distribution through any means other than regular usenet
channels is forbidden. It is forbidden to publish this
article in the Web, to change URIs of this article into links,
and to transfer the body without this notice, but quotations
of parts in other Usenet posts are allowed.
X-No-Archive: Yes
Archive: no
X-No-Archive-Readme: "X-No-Archive" is set, because this prevents some
services to mirror the article in the web. But the article may
be kept on a Usenet archive server with only NNTP access.
X-No-Html: yes
Content-Language: en-US
Accept-Language: de-DE, en-US, it, fr-FR
 by: Stefan Ram - Fri, 31 Dec 2021 12:04 UTC

Mateusz Viste <mateusz@xyz.invalid> writes:
>uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t tempo)
....
>In practical situations the end result of this computation is
>guaranteed to always fit inside an uint32_t, but the above formula
>overflows easily in the (ticks * tempo) part.

See the section

Multiplication

on the Web page

INT32-C. Ensure that operations on signed integers do not result in overflow

.

Re: How to avoid an overflow during multiplication?

<875yr554z4.fsf@bsb.me.uk>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19710&group=comp.lang.c#19710

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: ben.use...@bsb.me.uk (Ben Bacarisse)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 12:33:19 +0000
Organization: A noiseless patient Spider
Lines: 30
Message-ID: <875yr554z4.fsf@bsb.me.uk>
References: <sqmkg9$157v$1@gioia.aioe.org>
<multiplication-20211231130316@ram.dialup.fu-berlin.de>
Mime-Version: 1.0
Content-Type: text/plain
Injection-Info: reader02.eternal-september.org; posting-host="6433c3d3aa220a7b5ffca4a6245635e6";
logging-data="30094"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19gqIi46/lBSJXEuYDtJ3HLbIrBLpBTv+8="
Cancel-Lock: sha1:HFGeIAaRZnnsUkwJXogm7EK18as=
sha1:mOPoCVZjAfqU4ngachhSl4OHgbU=
X-BSB-Auth: 1.9dfe6df2933e525cabea.20211231123319GMT.875yr554z4.fsf@bsb.me.uk
 by: Ben Bacarisse - Fri, 31 Dec 2021 12:33 UTC

ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Mateusz Viste <mateusz@xyz.invalid> writes:
>>uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t tempo)
> ...
>>In practical situations the end result of this computation is
>>guaranteed to always fit inside an uint32_t, but the above formula
>>overflows easily in the (ticks * tempo) part.
>
> See the section
>
> Multiplication
>
> on the Web page
>
> INT32-C. Ensure that operations on signed integers do not result in
> overflow

What web page? I found a document (by searching for these words) but
that was all about detecting signed integer overflow. The OP does not
want to detect the overflow (technically, the wrapping since the types
are unsigned), but to get the right result even though the intermediate
calculation wraps.

Detecting the wrapping might be a first step, but the OP has a rough and
ready solution already, so anything that complicated is not going to be
suitable.

--
Ben.

Re: How to avoid an overflow during multiplication?

<8735m954yz.fsf@bsb.me.uk>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19711&group=comp.lang.c#19711

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: ben.use...@bsb.me.uk (Ben Bacarisse)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 12:33:24 +0000
Organization: A noiseless patient Spider
Lines: 66
Message-ID: <8735m954yz.fsf@bsb.me.uk>
References: <sqmkg9$157v$1@gioia.aioe.org>
Mime-Version: 1.0
Content-Type: text/plain
Injection-Info: reader02.eternal-september.org; posting-host="6433c3d3aa220a7b5ffca4a6245635e6";
logging-data="30094"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19egigFguQsYt4l46ykWb4JhJZcn5qwjgQ="
Cancel-Lock: sha1:m7BQ3bmXJgpwk8ZwEtegiwbU8c4=
sha1:VtBMJYyWlzN7MpLqjowhQq9sjl8=
X-BSB-Auth: 1.0c768023d64d95a57ab8.20211231123324GMT.8735m954yz.fsf@bsb.me.uk
 by: Ben Bacarisse - Fri, 31 Dec 2021 12:33 UTC

Mateusz Viste <mateusz@xyz.invalid> writes:

> I have this little function:
>
> /* converts an amount of ticks into human time (micro-seconds)
> * timeunits: number of ticks to convert into actual time
> * tempo : the time length (in microseconds) of grouplen ticks
> */
> uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t tempo)
> {
> return ticks * tempo / grouplen;
> }
>
> In practical situations the end result of this computation is
> guaranteed to always fit inside an uint32_t, but the above formula
> overflows easily in the (ticks * tempo) part.

There's a technical detail here which is that in C unsigned arithmetic
can't overflow. Arithmetic overflow is reserved for serious undefined
situation. Unsigned arithmetic just "wraps round" in a defined manner.

But there's nothing unclear about your question: the result is always <=
UINT32_MAX, but ticks * tempo isn't. You want to know how to calculate
the result correctly in all cases.

Interesting question. The obvious way is to use a wider type for the
multiplication (uint_least64_t) but that's probably not what you want.

> The easy & stupid way to avoid this overflow would be this:
>
> return ticks * (tempo / grouplen);
>
> ...but it's obviously not a good solution, since it may loose a lot of
> resolution. The hacky compromise that I currently use is this:
>
> return ticks * (((tempo << 3) / grouplen) >> 3);

I don't think this helps. I think that (when tempo << 3 does not wrap)
you get the same result as the original. Maybe I'm missing something.

> It works fine in my practical tests, so I might just as well be done
> with it, but I wonder if there is a cleaner approach to such seemingly
> simple problem?

I feel there should be a way, but I can't think of one right now.

> I should also add that this part of the program is performance
> critical, so I cannot afford branching or any other expensive
> computations. It's also worth noting that "grouplen" is guaranteed to
> be a positive number that never changes across the calls of the
> function (which, in truth, is not even a function, but it was easier to
> format it as such for this exercise).

Since grouplen does not change, can you find, at the start, gl1 and gl2,
ideally close to the square root of grouplen, so that you can use

(ticks / gl1) * (tempo / gl2)

instead? Obviously you may not be able to find such numbers, but there
may be constraints on grouplen that make this work.

> Mateusz
>

--
Ben.

Re: How to avoid an overflow during multiplication?

<sqmufp$7vc$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19712&group=comp.lang.c#19712

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: Bonita.M...@gmail.com (Bonita Montero)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 13:53:11 +0100
Organization: A noiseless patient Spider
Lines: 10
Message-ID: <sqmufp$7vc$1@dont-email.me>
References: <sqmkg9$157v$1@gioia.aioe.org>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Fri, 31 Dec 2021 12:53:13 -0000 (UTC)
Injection-Info: reader02.eternal-september.org; posting-host="ab6f9761d2812c8dbd0f41821392952f";
logging-data="8172"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+J5Aa/Xa+w1rQTcDAOOGZWSL7H0dYppRs="
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101
Thunderbird/91.4.1
Cancel-Lock: sha1:MRBeYxNu/wnqZUyb7PxhA821x5c=
In-Reply-To: <sqmkg9$157v$1@gioia.aioe.org>
Content-Language: de-DE
 by: Bonita Montero - Fri, 31 Dec 2021 12:53 UTC

Am 31.12.2021 um 11:02 schrieb Mateusz Viste:

> uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t tempo)
> {
> return ticks * tempo / grouplen;
return (uint32_t)((uint64_t)ticks * (uint64_t)tempo / grouplen);

On x86 f.e. the compiler will still use a 32 * 32 multiplication
because it sees that the casted value's upper halves are zero.
And after / grouplen you can safely cast the result to uint32_t.

Re: How to avoid an overflow during multiplication?

<bf365fe5-eee5-4794-9fc1-d8768ce980cen@googlegroups.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19713&group=comp.lang.c#19713

  copy link   Newsgroups: comp.lang.c
X-Received: by 2002:a05:622a:120b:: with SMTP id y11mr30591754qtx.544.1640956244406;
Fri, 31 Dec 2021 05:10:44 -0800 (PST)
X-Received: by 2002:a37:6113:: with SMTP id v19mr24556356qkb.333.1640956244257;
Fri, 31 Dec 2021 05:10:44 -0800 (PST)
Path: i2pn2.org!i2pn.org!weretis.net!feeder6.news.weretis.net!news.misty.com!border2.nntp.dca1.giganews.com!nntp.giganews.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c
Date: Fri, 31 Dec 2021 05:10:44 -0800 (PST)
In-Reply-To: <sqmufp$7vc$1@dont-email.me>
Injection-Info: google-groups.googlegroups.com; posting-host=94.246.251.164; posting-account=pysjKgkAAACLegAdYDFznkqjgx_7vlUK
NNTP-Posting-Host: 94.246.251.164
References: <sqmkg9$157v$1@gioia.aioe.org> <sqmufp$7vc$1@dont-email.me>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <bf365fe5-eee5-4794-9fc1-d8768ce980cen@googlegroups.com>
Subject: Re: How to avoid an overflow during multiplication?
From: oot...@hot.ee (Öö Tiib)
Injection-Date: Fri, 31 Dec 2021 13:10:44 +0000
Content-Type: text/plain; charset="UTF-8"
Lines: 14
 by: Öö Tiib - Fri, 31 Dec 2021 13:10 UTC

On Friday, 31 December 2021 at 14:53:24 UTC+2, Bonita Montero wrote:
> Am 31.12.2021 um 11:02 schrieb Mateusz Viste:
>
> > uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t tempo)
> > {
> > return ticks * tempo / grouplen;
> return (uint32_t)((uint64_t)ticks * (uint64_t)tempo / grouplen);
>
> On x86 f.e. the compiler will still use a 32 * 32 multiplication
> because it sees that the casted value's upper halves are zero.

I suspect that minority of programmers work on code that should
run on x86 right now. OP did not indicate that they are among such.

> And after / grouplen you can safely cast the result to uint32_t.

Re: How to avoid an overflow during multiplication?

<sqn0aq$1e8b$1@gioia.aioe.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19714&group=comp.lang.c#19714

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!aioe.org!299gYy2nqWB43X4cCBV6zg.user.46.165.242.75.POSTED!not-for-mail
From: mate...@xyz.invalid (Mateusz Viste)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 14:24:41 +0100
Organization: . . .
Message-ID: <sqn0aq$1e8b$1@gioia.aioe.org>
References: <sqmkg9$157v$1@gioia.aioe.org>
<8735m954yz.fsf@bsb.me.uk>
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="47371"; posting-host="299gYy2nqWB43X4cCBV6zg.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
X-Notice: Filtered by postfilter v. 0.9.2
 by: Mateusz Viste - Fri, 31 Dec 2021 13:24 UTC

2021-12-31 at 12:33 +0000, Ben Bacarisse wrote:
> There's a technical detail here which is that in C unsigned arithmetic
> can't overflow. Arithmetic overflow is reserved for serious undefined
> situation. Unsigned arithmetic just "wraps round" in a defined
> manner.

Can you provide the source please? I know that what you describe is the
standard behavior of all C compilers (that I know), but I could not
find the definition of multiplicative wrapping in the ISO 9899:1990
(yes, this is ANSI C). All I did find is this:

G.2 Undefined behavior
The behavior in the following circumstances is undefined:
(...)
-- An arithmetic operation is invalid (such as division or modulus by
0) or produces a result that cannot be represented in the space
provided (such as overflow or underflow)

> Interesting question. The obvious way is to use a wider type for the
> multiplication (uint_least64_t) but that's probably not what you want.

I should have mentioned that this runs on a 16-bit CPU. Doing 32-bit
multiplications is hard enough already, emulating 64-long types would
have a disastrous effect on performances. I also do not have access to
an FPU.

> > return ticks * (((tempo << 3) / grouplen) >> 3);
>
> I don't think this helps. I think that (when tempo << 3 does not
> wrap) you get the same result as the original. Maybe I'm missing
> something.

I'm sorry, you are correct of course. I copied the code wrong when
typing the message and misplaced one set of parenthesis. Here's the
actual hack I use:

return (ticks * (((tempo << 3) / grouplen))) >> 3;

> I feel there should be a way, but I can't think of one right now.

So we're on the same page.

On top of what I have already described, here is a short test program I
used to exhibit the problem and test for solutions:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main(int argc, char **argv) {
if (argc != 4) {
printf("usage: %s ticks tempo grouplen\n", argv[0]);
} else {
uint32_t r1, r2, r3, r4;
uint32_t ticks = atoi(argv[1]);
uint32_t tempo = atoi(argv[2]);
uint32_t grouplen = atoi(argv[3]);

r1 = ticks * tempo / grouplen;
r2 = ticks * (tempo / grouplen);
r3 = (ticks * (((tempo << 3) / grouplen))) >> 3;
r4 = (uint64_t)ticks * (uint64_t)tempo / grouplen;

printf("r1 = %u\nr2 = %u\nr3 = %u\nr4 = %u\n", r1, r2, r3, r4);
}
return 0;
}

And here how it runs with a set of real-life values that initially
borked my program:

../mul 9120 1090909 15370
r1 = 88429 <-- oops very bad
r2 = 638400 <-- more or less fine, but not very precise
r3 = 646380 <-- still not perfect, but acceptable precision
r4 = 647305 <-- perfect but slow

> Since grouplen does not change, can you find, at the start, gl1 and
> gl2, ideally close to the square root of grouplen, so that you can use
>
> (ticks / gl1) * (tempo / gl2)

I'm not sure I understand the goal here... Won't I still loose lots of
precision due to integer div rounding?

Mateusz

Re: How to avoid an overflow during multiplication?

<sqn0cl$i3l$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19715&group=comp.lang.c#19715

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: Bonita.M...@gmail.com (Bonita Montero)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 14:25:40 +0100
Organization: A noiseless patient Spider
Lines: 17
Message-ID: <sqn0cl$i3l$1@dont-email.me>
References: <sqmkg9$157v$1@gioia.aioe.org> <sqmufp$7vc$1@dont-email.me>
<bf365fe5-eee5-4794-9fc1-d8768ce980cen@googlegroups.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Fri, 31 Dec 2021 13:25:41 -0000 (UTC)
Injection-Info: reader02.eternal-september.org; posting-host="ab6f9761d2812c8dbd0f41821392952f";
logging-data="18549"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+MYsrBJmY45qhUql+LKE+9LLvZJCo63gE="
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101
Thunderbird/91.4.1
Cancel-Lock: sha1:bWZeRvBn7gOiVs6LENADOY3kj8U=
In-Reply-To: <bf365fe5-eee5-4794-9fc1-d8768ce980cen@googlegroups.com>
Content-Language: de-DE
 by: Bonita Montero - Fri, 31 Dec 2021 13:25 UTC

Am 31.12.2021 um 14:10 schrieb Öö Tiib:
> On Friday, 31 December 2021 at 14:53:24 UTC+2, Bonita Montero wrote:
>> Am 31.12.2021 um 11:02 schrieb Mateusz Viste:
>>
>>> uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t tempo)
>>> {
>>> return ticks * tempo / grouplen;
>> return (uint32_t)((uint64_t)ticks * (uint64_t)tempo / grouplen);
>>
>> On x86 f.e. the compiler will still use a 32 * 32 multiplication
>> because it sees that the casted value's upper halves are zero.
>
> I suspect that minority of programmers work on code that should
> run on x86 right now. OP did not indicate that they are among such.

There are a lot of CPUs that have Vx * Vx = V2x multiplications.
ARM also.

Re: How to avoid an overflow during multiplication?

<sqn0mp$1e8b$2@gioia.aioe.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19716&group=comp.lang.c#19716

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!aioe.org!299gYy2nqWB43X4cCBV6zg.user.46.165.242.75.POSTED!not-for-mail
From: mate...@xyz.invalid (Mateusz Viste)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 14:31:05 +0100
Organization: . . .
Message-ID: <sqn0mp$1e8b$2@gioia.aioe.org>
References: <sqmkg9$157v$1@gioia.aioe.org>
<sqmufp$7vc$1@dont-email.me>
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="47371"; posting-host="299gYy2nqWB43X4cCBV6zg.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
X-Notice: Filtered by postfilter v. 0.9.2
 by: Mateusz Viste - Fri, 31 Dec 2021 13:31 UTC

2021-12-31 at 13:53 +0100, Bonita Montero wrote:
> Am 31.12.2021 um 11:02 schrieb Mateusz Viste:
>
> > uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t
> > tempo) {
> > return ticks * tempo / grouplen;
> return (uint32_t)((uint64_t)ticks * (uint64_t)tempo / grouplen);
>
> On x86 f.e. the compiler will still use a 32 * 32 multiplication
> because it sees that the casted value's upper halves are zero.
> And after / grouplen you can safely cast the result to uint32_t.

I should have mentioned what CPU I run this on, my bad. It is an Intel
80C86. 7 MHz, no FPU. Using 64 bits in any way is not really an option.

The machine is this one specifically: https://youtu.be/8ssDGBTssUI?t=97

Mateusz

Re: How to avoid an overflow during multiplication?

<ca774586-49c6-4f46-9dd1-f39df2231dd1n@googlegroups.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19717&group=comp.lang.c#19717

  copy link   Newsgroups: comp.lang.c
X-Received: by 2002:ac8:5f47:: with SMTP id y7mr30320652qta.342.1640957825963;
Fri, 31 Dec 2021 05:37:05 -0800 (PST)
X-Received: by 2002:a05:622a:4c:: with SMTP id y12mr31166879qtw.21.1640957825847;
Fri, 31 Dec 2021 05:37:05 -0800 (PST)
Path: i2pn2.org!i2pn.org!weretis.net!feeder6.news.weretis.net!news.misty.com!border2.nntp.dca1.giganews.com!nntp.giganews.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c
Date: Fri, 31 Dec 2021 05:37:05 -0800 (PST)
In-Reply-To: <sqmkg9$157v$1@gioia.aioe.org>
Injection-Info: google-groups.googlegroups.com; posting-host=2a0d:6fc2:55b0:ca00:f0ca:a00:bde2:2cc1;
posting-account=ow8VOgoAAAAfiGNvoH__Y4ADRwQF1hZW
NNTP-Posting-Host: 2a0d:6fc2:55b0:ca00:f0ca:a00:bde2:2cc1
References: <sqmkg9$157v$1@gioia.aioe.org>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <ca774586-49c6-4f46-9dd1-f39df2231dd1n@googlegroups.com>
Subject: Re: How to avoid an overflow during multiplication?
From: already5...@yahoo.com (Michael S)
Injection-Date: Fri, 31 Dec 2021 13:37:05 +0000
Content-Type: text/plain; charset="UTF-8"
Lines: 43
 by: Michael S - Fri, 31 Dec 2021 13:37 UTC

On Friday, December 31, 2021 at 12:03:00 PM UTC+2, Mateusz Viste wrote:
> I have this little function:
>
> /* converts an amount of ticks into human time (micro-seconds)
> * timeunits: number of ticks to convert into actual time
> * tempo : the time length (in microseconds) of grouplen ticks
> */
> uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t tempo)
> {
> return ticks * tempo / grouplen;
> }
>
> In practical situations the end result of this computation is
> guaranteed to always fit inside an uint32_t, but the above formula
> overflows easily in the (ticks * tempo) part.
>
> The easy & stupid way to avoid this overflow would be this:
>
> return ticks * (tempo / grouplen);
>
> ...but it's obviously not a good solution, since it may loose a lot of
> resolution. The hacky compromise that I currently use is this:
>
> return ticks * (((tempo << 3) / grouplen) >> 3);
>
> It works fine in my practical tests, so I might just as well be done
> with it, but I wonder if there is a cleaner approach to such seemingly
> simple problem?
>
> I should also add that this part of the program is performance
> critical, so I cannot afford branching or any other expensive
> computations. It's also worth noting that "grouplen" is guaranteed to
> be a positive number that never changes across the calls of the
> function (which, in truth, is not even a function, but it was easier to
> format it as such for this exercise).
>
> Mateusz

Couple of questions:
1. You said that grouplen never changes. Does it imply that tempo could change?
2. What is maximal expected value of ticks?
3. If the result is for human consumption, how could it be performance-critical? Humans are sloooooow.

Re: How to avoid an overflow during multiplication?

<sqn13f$n37$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19718&group=comp.lang.c#19718

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: Bonita.M...@gmail.com (Bonita Montero)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 14:37:50 +0100
Organization: A noiseless patient Spider
Lines: 7
Message-ID: <sqn13f$n37$1@dont-email.me>
References: <sqmkg9$157v$1@gioia.aioe.org> <sqmufp$7vc$1@dont-email.me>
<sqn0mp$1e8b$2@gioia.aioe.org>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Fri, 31 Dec 2021 13:37:51 -0000 (UTC)
Injection-Info: reader02.eternal-september.org; posting-host="ab6f9761d2812c8dbd0f41821392952f";
logging-data="23655"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/q5bdwZIGl9QzgEaAb7yDXJkuFQsn+9RU="
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101
Thunderbird/91.4.1
Cancel-Lock: sha1:3tuoszfTxTIOcQ3Z021IpELBajE=
In-Reply-To: <sqn0mp$1e8b$2@gioia.aioe.org>
Content-Language: de-DE
 by: Bonita Montero - Fri, 31 Dec 2021 13:37 UTC

Am 31.12.2021 um 14:31 schrieb Mateusz Viste:

> I should have mentioned what CPU I run this on, my bad. It is an Intel
> 80C86. 7 MHz, no FPU. Using 64 bits in any way is not really an option.

If a * b overflows you have no option other than using 64 bits if you
want to have an exact result.

Re: How to avoid an overflow during multiplication?

<unsigned-20211231144041@ram.dialup.fu-berlin.de>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19719&group=comp.lang.c#19719

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: ram...@zedat.fu-berlin.de (Stefan Ram)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: 31 Dec 2021 13:41:17 GMT
Organization: Stefan Ram
Lines: 16
Expires: 1 Apr 2022 11:59:58 GMT
Message-ID: <unsigned-20211231144041@ram.dialup.fu-berlin.de>
References: <sqmkg9$157v$1@gioia.aioe.org> <8735m954yz.fsf@bsb.me.uk> <sqn0aq$1e8b$1@gioia.aioe.org>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Trace: news.uni-berlin.de /TEsNn4VS0z0LOKwa//PagFMEgsIR/T+rGy2hzcp7zhkG8
X-Copyright: (C) Copyright 2021 Stefan Ram. All rights reserved.
Distribution through any means other than regular usenet
channels is forbidden. It is forbidden to publish this
article in the Web, to change URIs of this article into links,
and to transfer the body without this notice, but quotations
of parts in other Usenet posts are allowed.
X-No-Archive: Yes
Archive: no
X-No-Archive-Readme: "X-No-Archive" is set, because this prevents some
services to mirror the article in the web. But the article may
be kept on a Usenet archive server with only NNTP access.
X-No-Html: yes
Content-Language: en-US
Accept-Language: de-DE, en-US, it, fr-FR
 by: Stefan Ram - Fri, 31 Dec 2021 13:41 UTC

Mateusz Viste <mateusz@xyz.invalid> wrote:
>2021-12-31 at 12:33 +0000, Ben Bacarisse wrote:
>>There's a technical detail here which is that in C unsigned arithmetic
>>can't overflow. Arithmetic overflow is reserved for serious undefined
>>situation. Unsigned arithmetic just "wraps round" in a defined
>>manner.
>Can you provide the source please? I know that what you describe is the

|A computation involving unsigned operands can never overflow,
|because a result that cannot be represented by the resulting
|unsigned integer type is reduced modulo the number that is
|one greater than the largest value that can be represented by
|the resulting type.
n2310, 6.2.5p9

Re: How to avoid an overflow during multiplication?

<sqn24c$14ld$1@gioia.aioe.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19720&group=comp.lang.c#19720

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!aioe.org!299gYy2nqWB43X4cCBV6zg.user.46.165.242.75.POSTED!not-for-mail
From: mate...@xyz.invalid (Mateusz Viste)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 14:55:24 +0100
Organization: . . .
Message-ID: <sqn24c$14ld$1@gioia.aioe.org>
References: <sqmkg9$157v$1@gioia.aioe.org>
<ca774586-49c6-4f46-9dd1-f39df2231dd1n@googlegroups.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="37549"; posting-host="299gYy2nqWB43X4cCBV6zg.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
X-Notice: Filtered by postfilter v. 0.9.2
 by: Mateusz Viste - Fri, 31 Dec 2021 13:55 UTC

2021-12-31 at 05:37 -0800, Michael S wrote:
> Couple of questions:
> 1. You said that grouplen never changes. Does it imply that tempo
> could change?

Yes, tempo can change during a song play.

> 2. What is maximal expected value of ticks?

Hard to say as there is no theoretical limit. In practice I have never
seen any value above like 10 * tempo, and tempo maxes out at about
2'000'000 (which translates to 30 BPM in the MIDI world). So we could
say that ticks is not expected to go above 20'000'000.

> 3. If the result is for human consumption, how could it be
> performance-critical? Humans are sloooooow.

Not when it comes to hearing frequencies and rhythm. The code is a MIDI
scheduler that computes the timing of individual MIDI notes. A
millisecond resolution is fine, but anything less starts to sound
laggy. This is why I compute everything in microseconds (as does MIDI
itself). One of the options I was pondering was to convert all values
into 1/10th of milliseconds and do computations on this... But it's an
even uglier approach than what I do now.

Mateusz

Re: How to avoid an overflow during multiplication?

<sqn2dj$14ld$2@gioia.aioe.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19721&group=comp.lang.c#19721

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!aioe.org!299gYy2nqWB43X4cCBV6zg.user.46.165.242.75.POSTED!not-for-mail
From: mate...@xyz.invalid (Mateusz Viste)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 15:00:18 +0100
Organization: . . .
Message-ID: <sqn2dj$14ld$2@gioia.aioe.org>
References: <sqmkg9$157v$1@gioia.aioe.org>
<8735m954yz.fsf@bsb.me.uk>
<sqn0aq$1e8b$1@gioia.aioe.org>
<unsigned-20211231144041@ram.dialup.fu-berlin.de>
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="37549"; posting-host="299gYy2nqWB43X4cCBV6zg.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
X-Notice: Filtered by postfilter v. 0.9.2
 by: Mateusz Viste - Fri, 31 Dec 2021 14:00 UTC

2021-12-31 at 13:41 GMT, Stefan Ram wrote:
> |A computation involving unsigned operands can never overflow,
> |because a result that cannot be represented by the resulting
> |unsigned integer type is reduced modulo the number that is
> |one greater than the largest value that can be represented by
> |the resulting type.
> n2310, 6.2.5p9

Had missed that one, thanks!

(In my ANSI C copy it is at 6.1.2.5, p23)

Mateusz

Re: How to avoid an overflow during multiplication?

<d9928f83-2dd3-4943-8938-de5627d9f05fn@googlegroups.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19722&group=comp.lang.c#19722

  copy link   Newsgroups: comp.lang.c
X-Received: by 2002:a05:620a:454a:: with SMTP id u10mr25738196qkp.605.1640959959242;
Fri, 31 Dec 2021 06:12:39 -0800 (PST)
X-Received: by 2002:a37:315:: with SMTP id 21mr24467141qkd.52.1640959959105;
Fri, 31 Dec 2021 06:12:39 -0800 (PST)
Path: i2pn2.org!i2pn.org!weretis.net!feeder6.news.weretis.net!news.misty.com!border2.nntp.dca1.giganews.com!nntp.giganews.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c
Date: Fri, 31 Dec 2021 06:12:38 -0800 (PST)
In-Reply-To: <sqn24c$14ld$1@gioia.aioe.org>
Injection-Info: google-groups.googlegroups.com; posting-host=2a0d:6fc2:55b0:ca00:f0ca:a00:bde2:2cc1;
posting-account=ow8VOgoAAAAfiGNvoH__Y4ADRwQF1hZW
NNTP-Posting-Host: 2a0d:6fc2:55b0:ca00:f0ca:a00:bde2:2cc1
References: <sqmkg9$157v$1@gioia.aioe.org> <ca774586-49c6-4f46-9dd1-f39df2231dd1n@googlegroups.com>
<sqn24c$14ld$1@gioia.aioe.org>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <d9928f83-2dd3-4943-8938-de5627d9f05fn@googlegroups.com>
Subject: Re: How to avoid an overflow during multiplication?
From: already5...@yahoo.com (Michael S)
Injection-Date: Fri, 31 Dec 2021 14:12:39 +0000
Content-Type: text/plain; charset="UTF-8"
Lines: 39
 by: Michael S - Fri, 31 Dec 2021 14:12 UTC

On Friday, December 31, 2021 at 3:55:35 PM UTC+2, Mateusz Viste wrote:
> 2021-12-31 at 05:37 -0800, Michael S wrote:
> > Couple of questions:
> > 1. You said that grouplen never changes. Does it imply that tempo
> > could change?
> Yes, tempo can change during a song play.

Then it's tough.
Still, if we can divide it into two parts, something like
void SetTempo(uint32_t grouplen, uint16_t tempo) that calculates
A = tempo/grouplen
B = ((tempo%grouplen) * 128)/grouplen
and
uint32_t ticks2time(uint32_t ticks) that uses A and B
and if SetTempo() is called many times less often than ticks2time() then situation could be improved.

> > 2. What is maximal expected value of ticks?
> Hard to say as there is no theoretical limit. In practice I have never
> seen any value above like 10 * tempo, and tempo maxes out at about
> 2'000'000 (which translates to 30 BPM in the MIDI world). So we could
> say that ticks is not expected to go above 20'000'000.

So, multiplication of ticks by number B in range 0:127 is o.k.

> > 3. If the result is for human consumption, how could it be
> > performance-critical? Humans are sloooooow.
> Not when it comes to hearing frequencies and rhythm. The code is a MIDI
> scheduler that computes the timing of individual MIDI notes. A
> millisecond resolution is fine, but anything less starts to sound
> laggy. This is why I compute everything in microseconds (as does MIDI
> itself). One of the options I was pondering was to convert all values
> into 1/10th of milliseconds and do computations on this... But it's an
> even uglier approach than what I do now.

I still don't understand, but so be it.

>
> Mateusz

Re: How to avoid an overflow during multiplication?

<sqn6j3$1utr$1@gioia.aioe.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19723&group=comp.lang.c#19723

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!aioe.org!299gYy2nqWB43X4cCBV6zg.user.46.165.242.75.POSTED!not-for-mail
From: mate...@xyz.invalid (Mateusz Viste)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 16:11:31 +0100
Organization: . . .
Message-ID: <sqn6j3$1utr$1@gioia.aioe.org>
References: <sqmkg9$157v$1@gioia.aioe.org>
<ca774586-49c6-4f46-9dd1-f39df2231dd1n@googlegroups.com>
<sqn24c$14ld$1@gioia.aioe.org>
<d9928f83-2dd3-4943-8938-de5627d9f05fn@googlegroups.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="64443"; posting-host="299gYy2nqWB43X4cCBV6zg.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
X-Notice: Filtered by postfilter v. 0.9.2
 by: Mateusz Viste - Fri, 31 Dec 2021 15:11 UTC

2021-12-31 at 06:12 -0800, Michael S wrote:
> On Friday, December 31, 2021 at 3:55:35 PM UTC+2, Mateusz Viste wrote:
> > 2021-12-31 at 05:37 -0800, Michael S wrote:
> > > Couple of questions:
> > > 1. You said that grouplen never changes. Does it imply that tempo
> > > could change?
> > Yes, tempo can change during a song play.
>
> Then it's tough.

There are many constraints, yes.

> Still, if we can divide it into two parts, something like
> void SetTempo(uint32_t grouplen, uint16_t tempo) that calculates
> A = tempo/grouplen
> B = ((tempo%grouplen) * 128)/grouplen
> and
> uint32_t ticks2time(uint32_t ticks) that uses A and B
> and if SetTempo() is called many times less often than ticks2time()
> then situation could be improved.

You mean this, right?

uint32_t A = tempo / grouplen;
uint32_t B = (tempo % grouplen) * 128 / grouplen;
return ticks * A + (ticks * B) / 128;

another way to express it would be this:

return ticks * (tempo / grouplen) +
((ticks * (((tempo % grouplen) << 7) / grouplen)) >> 7);

This is close to my solution with bit shifting, but if I get it right
yours is more resilient to wraparounds as it only shifts a remainder
and not the whole tempo. Thanks for the pointer!

> I still don't understand, but so be it.

Another way to say it would be that the CPU is so slow that it
struggles with its current tasks so it doesn't have much time to fiddle
around with too much math (esp. 32-bit math). :)

Mateusz

Re: How to avoid an overflow during multiplication?

<20211231062510.664@kylheku.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19724&group=comp.lang.c#19724

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: 480-992-...@kylheku.com (Kaz Kylheku)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 15:13:06 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 111
Message-ID: <20211231062510.664@kylheku.com>
References: <sqmkg9$157v$1@gioia.aioe.org>
Injection-Date: Fri, 31 Dec 2021 15:13:06 -0000 (UTC)
Injection-Info: reader02.eternal-september.org; posting-host="f33ade962264782c77fca989b50d5f03";
logging-data="27301"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18LGQYFUtOcSCOm+jTs55DdOlmszI9vVfU="
User-Agent: slrn/1.0.3 (Linux)
Cancel-Lock: sha1:/Wj/QNJ8iKIpL4NZ/jorP7Hbw30=
 by: Kaz Kylheku - Fri, 31 Dec 2021 15:13 UTC

On 2021-12-31, Mateusz Viste <mateusz@xyz.invalid> wrote:
> I have this little function:
>
> /* converts an amount of ticks into human time (micro-seconds)
> * timeunits: number of ticks to convert into actual time

There is no timeunits parameter; is that ticks?

> * tempo : the time length (in microseconds) of grouplen ticks
> */
> uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t tempo)
> {
> return ticks * tempo / grouplen;
> }

Ticks are often longer than a microsecond, so it can be
resonably expected that tempo / grouplen > 1.

E.g. a 1000 Hz timer interrupt produces 1000 us ticks. We multiply
by 1000 to go from ticks to seconds. If ticks can go to UINT32_MAX,
then we cannot go to microseconds in 32 bit.

Therefore, this calculation has an inherent global overflow problem,
even if you address the local overflow in the multiplication.

We need:

(uint64_t) ticks * tempo / grouplen;

Computer Associates (of Accpac: see
https://en.wikipedia.org/wiki/Sage_300#History) used this as an interview
question all the time 30 years ago: how to do this kind of scaling
without overflow when the fraction is <= 1. E.g. for calculating
a percentage: X * 100 / Y, where X <= Y.

(Someone in management had used a calculation like this in displaying
free memory in the application years before that or something and were
super proud of their achievement, like that they are Knuth-level talent
and only such others should ever be hired.)

The trick is simply to scale the fraction X/Y down to make it smaller,
so that the multiplication has the headroom for avoiding overflow.

If we knew gcd(X, Y), we could divide X and Y by that to get an exact
equivalent in lowest terms; but that might be enough to eliminate the
overflow. Or even to do anything at all: what if gcd(X, Y) == 1?

What you can do is right shift X and Y until you have enough headroom
for the multiplication:

/* while the multiplication overflows, scale the fraction down */

while (ticks * tempo < ticks) {
ticks /= 2; /* compiles to a right shift */
grouplen /= 2;
}

/* [here, handle grouplen having vanished to zero] */

return ticks * tempo / grouplen;

> The easy & stupid way to avoid this overflow would be this:

> return ticks * (tempo / grouplen);

If the fraction is greater than 1 but grouplen isn't a divisor of
tempo, it's can be horribly inaccurate.

> ...but it's obviously not a good solution, since it may loose a lot of
> resolution. The hacky compromise that I currently use is this:

That will be completely useless in integer math if the fraction is < 1,
because then tempo / guardian is always zero, and it can be horribly
inaccurate when the fraction is > 1.

Supose tempo were *almost* twice grouplen, like 511/256. That
evaluates to 1. It's almost 100% off.

>
> return ticks * (((tempo << 3) / grouplen) >> 3);

So, if if a fixed shift works, you still want to do the multiplication
first, then division, for a better approximation.

return ticks * (tempo / 8) / (grouplen / 8);

I.e. same as pre-scaling the fraction:

tempo /= 8;
grouplen /= 8; /* could be zero! */
return ticks * tempo / grouplen;

This will only work if you know that the ticks value is always small
enough relative to tempo that three bits of headroom is enough.

E.g in our 511/256 example, after scaling by / 8 we get X * 63 / 64.
It's off, but nowhere near as much.

> computations. It's also worth noting that "grouplen" is guaranteed to
> be a positive number that never changes across the calls of the
> function (which, in truth, is not even a function, but it was easier to
> format it as such for this exercise).

OK, so then there may be a way to check somewhere else that the scaled
value grouplen / 8 is nonzero, to avoid division by zero, without
doing that for every calculation.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

Re: How to avoid an overflow during multiplication?

<sqn6ur$sdn$1@dont-email.me>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19725&group=comp.lang.c#19725

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: david.br...@hesbynett.no (David Brown)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 16:17:46 +0100
Organization: A noiseless patient Spider
Lines: 28
Message-ID: <sqn6ur$sdn$1@dont-email.me>
References: <sqmkg9$157v$1@gioia.aioe.org> <8735m954yz.fsf@bsb.me.uk>
<sqn0aq$1e8b$1@gioia.aioe.org>
Mime-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Fri, 31 Dec 2021 15:17:47 -0000 (UTC)
Injection-Info: reader02.eternal-september.org; posting-host="b454e564db563d9b651013bbaa3e0164";
logging-data="29111"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+a3zu2dnJfIUqVtzqwlE2r93Xz6PHPoyw="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101
Thunderbird/78.11.0
Cancel-Lock: sha1:FZYzA5ySmLCGiJm9ZQQmSY97BF4=
In-Reply-To: <sqn0aq$1e8b$1@gioia.aioe.org>
Content-Language: en-GB
 by: David Brown - Fri, 31 Dec 2021 15:17 UTC

On 31/12/2021 14:24, Mateusz Viste wrote:

> I'm sorry, you are correct of course. I copied the code wrong when
> typing the message and misplaced one set of parenthesis. Here's the
> actual hack I use:
>
> return (ticks * (((tempo << 3) / grouplen))) >> 3;
>
Hacks like that are common and, IMHO, entirely reasonable on limited
power small systems. I've used them regularly.

The risk, however, is that you make mistakes about when things can
overflow - particularly if something changes. It can all work fine for
a while until someone changes a scaling constant or range limits
somewhere else in the program, and you've got a silent bug.

Often you can reduce that risk by having the value "3" here calculated
automatically from the ranges, or at least defined in the same place as
any other relevant constants along with suitable comments. If you can,
it is a good idea to use static assertions to get compile-time failures
if something is going to go wrong:

_Static_assert(MAX_TICKS * ((tempo << 3) / grouplen)) < 0x100000000,
"Check that multiplication does not overflow");

"_Static_assert" was introduced in C11, but you can use macro-based
equivalents prior to that. I can post a useable definition if you need one.

Re: How to avoid an overflow during multiplication?

<20211231071349.923@kylheku.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19726&group=comp.lang.c#19726

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: 480-992-...@kylheku.com (Kaz Kylheku)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 15:19:13 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 12
Message-ID: <20211231071349.923@kylheku.com>
References: <sqmkg9$157v$1@gioia.aioe.org>
<ca774586-49c6-4f46-9dd1-f39df2231dd1n@googlegroups.com>
<sqn24c$14ld$1@gioia.aioe.org>
Injection-Date: Fri, 31 Dec 2021 15:19:13 -0000 (UTC)
Injection-Info: reader02.eternal-september.org; posting-host="f33ade962264782c77fca989b50d5f03";
logging-data="27301"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+/xIRxHy0IInpVayDeWKCFSgVx8pjZoJQ="
User-Agent: slrn/1.0.3 (Linux)
Cancel-Lock: sha1:pN8k6Zsn7Zmctde1KvDG13T2Tec=
 by: Kaz Kylheku - Fri, 31 Dec 2021 15:19 UTC

On 2021-12-31, Mateusz Viste <mateusz@xyz.invalid> wrote:
> Not when it comes to hearing frequencies and rhythm. The code is a MIDI
> scheduler that computes the timing of individual MIDI notes. A
> millisecond resolution is fine, but anything less starts to sound
> laggy.

If you stand 3 meters away from your guitar amp stack, it takes 9
milliseconds to hear it due to speed of sound in air.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

Re: How to avoid an overflow during multiplication?

<sqn77c$1utr$2@gioia.aioe.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19727&group=comp.lang.c#19727

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!aioe.org!299gYy2nqWB43X4cCBV6zg.user.46.165.242.75.POSTED!not-for-mail
From: mate...@xyz.invalid (Mateusz Viste)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 16:22:20 +0100
Organization: . . .
Message-ID: <sqn77c$1utr$2@gioia.aioe.org>
References: <sqmkg9$157v$1@gioia.aioe.org>
<8735m954yz.fsf@bsb.me.uk>
<sqn0aq$1e8b$1@gioia.aioe.org>
<sqn6ur$sdn$1@dont-email.me>
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="64443"; posting-host="299gYy2nqWB43X4cCBV6zg.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
X-Notice: Filtered by postfilter v. 0.9.2
 by: Mateusz Viste - Fri, 31 Dec 2021 15:22 UTC

2021-12-31 at 16:17 +0100, David Brown wrote:
> > return (ticks * (((tempo << 3) / grouplen))) >> 3;
> >
> Hacks like that are common and, IMHO, entirely reasonable on limited
> power small systems. I've used them regularly.

Ah, so I didn't invent anything... again.
Good, so it's not as stupid as I initially thought then.

> Often you can reduce that risk by having the value "3" here calculated
> automatically from the ranges, or at least defined in the same place
> as any other relevant constants along with suitable comments. If you
> can, it is a good idea to use static assertions to get compile-time
> failures if something is going to go wrong

Good idea. Thanks!

Mateusz

Re: How to avoid an overflow during multiplication?

<sqn7b3$1utr$3@gioia.aioe.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19728&group=comp.lang.c#19728

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!aioe.org!299gYy2nqWB43X4cCBV6zg.user.46.165.242.75.POSTED!not-for-mail
From: mate...@xyz.invalid (Mateusz Viste)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 16:24:19 +0100
Organization: . . .
Message-ID: <sqn7b3$1utr$3@gioia.aioe.org>
References: <sqmkg9$157v$1@gioia.aioe.org>
<ca774586-49c6-4f46-9dd1-f39df2231dd1n@googlegroups.com>
<sqn24c$14ld$1@gioia.aioe.org>
<20211231071349.923@kylheku.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="64443"; posting-host="299gYy2nqWB43X4cCBV6zg.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
X-Notice: Filtered by postfilter v. 0.9.2
 by: Mateusz Viste - Fri, 31 Dec 2021 15:24 UTC

2021-12-31 at 15:19 -0000, Kaz Kylheku wrote:
> On 2021-12-31, Mateusz Viste <mateusz@xyz.invalid> wrote:
> > Not when it comes to hearing frequencies and rhythm. The code is a
> > MIDI scheduler that computes the timing of individual MIDI notes. A
> > millisecond resolution is fine, but anything less starts to sound
> > laggy.
>
> If you stand 3 meters away from your guitar amp stack, it takes 9
> milliseconds to hear it due to speed of sound in air.

Sure, lag is fine (in this context), but jitter is not.

I guess I should have said "sounds jitterish" in lieu of "sounds laggy".
Semantics. :)

Mateusz

Re: How to avoid an overflow during multiplication?

<sqn9ee$1utr$4@gioia.aioe.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19729&group=comp.lang.c#19729

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!aioe.org!299gYy2nqWB43X4cCBV6zg.user.46.165.242.75.POSTED!not-for-mail
From: mate...@xyz.invalid (Mateusz Viste)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 17:00:14 +0100
Organization: . . .
Message-ID: <sqn9ee$1utr$4@gioia.aioe.org>
References: <sqmkg9$157v$1@gioia.aioe.org>
<20211231062510.664@kylheku.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="64443"; posting-host="299gYy2nqWB43X4cCBV6zg.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
X-Notice: Filtered by postfilter v. 0.9.2
 by: Mateusz Viste - Fri, 31 Dec 2021 16:00 UTC

2021-12-31 at 15:13 -0000, Kaz Kylheku wrote:
> There is no timeunits parameter; is that ticks?

Yes. I reworked the message a few times before posting to make it as
clear as possible, and of course added mistakes along the way...

> Ticks are often longer than a microsecond, so it can be
> resonably expected that tempo / grouplen > 1.

Actually, ticks are not a unit of time. Tempo is a unit of time
(in MIDI terms it's the length, in microseconds, of a quarter note).
Grouplen is the number of "ticks" (also called "unit time") in a quarter
note (which is also called a "beat").

But this does not matter anyway and I do not want to bore you to death.
In any case you are correct that tempo is likely to be greater than
grouplen, even though in theory it does not have to. Usually there's at
least a 100:1 relation between tempo and grouplen.

> E.g. a 1000 Hz timer interrupt produces 1000 us ticks. We multiply
> by 1000 to go from ticks to seconds. If ticks can go to UINT32_MAX,
> then we cannot go to microseconds in 32 bit.
>
> Therefore, this calculation has an inherent global overflow problem,
> even if you address the local overflow in the multiplication.

Nah, it works just fine. :)

The end result is a number of microseconds that represents the
delta-time of a MIDI note (that is "when will the next note occur").
2^32 microseconds is 71 minutes. I know no MIDI file that has such long
pauses in between notes. Sure, one could craft such abomination, but it
is not my ambition to cover such edge cases.

> What you can do is right shift X and Y until you have enough headroom
> for the multiplication:
>
> /* while the multiplication overflows, scale the fraction down */
> while (ticks * tempo < ticks) {
> ticks /= 2; /* compiles to a right shift */
> grouplen /= 2;
> }

Yes, that would be a good solution, if there was no time constraints.
The above loop is rich on branching and may lead to many
multiplications... That's a lot of cycles (for a 4 MHz CPU).

> > return ticks * (tempo / grouplen);
>
> If the fraction is greater than 1 but grouplen isn't a divisor of
> tempo, it's can be horribly inaccurate.

Yes, it is true. Fortunately in practice tempo is much higher than
grouplen, so the practical accuracy of this computation on "normal"
MIDI files is around 92-98%. Not perfect, but hard to hear. I then
added my bit-shifting hack which bumped accuracy to 98-99% - but with
some theoretical risk of introducing new overflows. Hence I was curious
what other people do in similar circumstances.

> > return ticks * (((tempo << 3) / grouplen) >> 3);
>
> So, if if a fixed shift works, you still want to do the multiplication
> first, then division, for a better approximation.
>
> return ticks * (tempo / 8) / (grouplen / 8);

I didn't thought of that, it's actually pretty neat - and
straightforward, too! With the only risk being that the CPU will burn
in flames if grouplen happens to be < 8 (but that's easy to check out of
the critical loop since grouplen never changes).

> > computations. It's also worth noting that "grouplen" is guaranteed
> > to be a positive number that never changes across the calls of the
> > function (which, in truth, is not even a function, but it was
> > easier to format it as such for this exercise).
>
> OK, so then there may be a way to check somewhere else that the scaled
> value grouplen / 8 is nonzero, to avoid division by zero, without
> doing that for every calculation.

Precisely, yes. I will do tests. Thank you for your input!

Mateusz

Re: How to avoid an overflow during multiplication?

<_1GzJ.9375$PNM6.4266@fx09.iad>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19730&group=comp.lang.c#19730

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!paganini.bofh.team!news.dns-netz.com!news.freedyn.de!newsreader4.netcologne.de!news.netcologne.de!peer03.ams1!peer.ams1.xlned.com!news.xlned.com!peer03.iad!feed-me.highwinds-media.com!news.highwinds-media.com!fx09.iad.POSTED!not-for-mail
X-newsreader: xrn 9.03-beta-14-64bit
Sender: scott@dragon.sl.home (Scott Lurndal)
From: sco...@slp53.sl.home (Scott Lurndal)
Reply-To: slp53@pacbell.net
Subject: Re: How to avoid an overflow during multiplication?
Newsgroups: comp.lang.c
References: <sqmkg9$157v$1@gioia.aioe.org> <sqmufp$7vc$1@dont-email.me> <bf365fe5-eee5-4794-9fc1-d8768ce980cen@googlegroups.com>
Lines: 17
Message-ID: <_1GzJ.9375$PNM6.4266@fx09.iad>
X-Complaints-To: abuse@usenetserver.com
NNTP-Posting-Date: Fri, 31 Dec 2021 16:16:58 UTC
Organization: UsenetServer - www.usenetserver.com
Date: Fri, 31 Dec 2021 16:16:58 GMT
X-Received-Bytes: 1489
 by: Scott Lurndal - Fri, 31 Dec 2021 16:16 UTC

=?UTF-8?B?w5bDtiBUaWli?= <ootiib@hot.ee> writes:
>On Friday, 31 December 2021 at 14:53:24 UTC+2, Bonita Montero wrote:
>> Am 31.12.2021 um 11:02 schrieb Mateusz Viste:
>>
>> > uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t tempo)
>> > {
>> > return ticks * tempo / grouplen;
>> return (uint32_t)((uint64_t)ticks * (uint64_t)tempo / grouplen);
>>
>> On x86 f.e. the compiler will still use a 32 * 32 multiplication
>> because it sees that the casted value's upper halves are zero.
>
>I suspect that minority of programmers work on code that should
>run on x86 right now. OP did not indicate that they are among such.

Indeed, and the OP subsequently clarified that it is a 16-bit
microcontroller.

Re: How to avoid an overflow during multiplication?

<sqnbbd$1q1e$1@gioia.aioe.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19731&group=comp.lang.c#19731

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!aioe.org!299gYy2nqWB43X4cCBV6zg.user.46.165.242.75.POSTED!not-for-mail
From: mate...@xyz.invalid (Mateusz Viste)
Newsgroups: comp.lang.c
Subject: Re: How to avoid an overflow during multiplication?
Date: Fri, 31 Dec 2021 17:32:44 +0100
Organization: . . .
Message-ID: <sqnbbd$1q1e$1@gioia.aioe.org>
References: <sqmkg9$157v$1@gioia.aioe.org>
<sqmufp$7vc$1@dont-email.me>
<bf365fe5-eee5-4794-9fc1-d8768ce980cen@googlegroups.com>
<_1GzJ.9375$PNM6.4266@fx09.iad>
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="59438"; posting-host="299gYy2nqWB43X4cCBV6zg.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
X-Notice: Filtered by postfilter v. 0.9.2
 by: Mateusz Viste - Fri, 31 Dec 2021 16:32 UTC

2021-12-31 at 16:16 GMT, Scott Lurndal wrote:
> =?UTF-8?B?w5bDtiBUaWli?= <ootiib@hot.ee> writes:
> >On Friday, 31 December 2021 at 14:53:24 UTC+2, Bonita Montero wrote:
> >
> >> Am 31.12.2021 um 11:02 schrieb Mateusz Viste:
> >>
> >> > uint32_t ticks2time(uint32_t ticks, uint32_t grouplen, uint16_t
> >> > tempo) {
> >> > return ticks * tempo / grouplen;
> >> return (uint32_t)((uint64_t)ticks * (uint64_t)tempo / grouplen);
> >>
> >> On x86 f.e. the compiler will still use a 32 * 32 multiplication
> >> because it sees that the casted value's upper halves are zero.
> >
> >I suspect that minority of programmers work on code that should
> >run on x86 right now. OP did not indicate that they are among such.
> >
>
> Indeed, and the OP subsequently clarified that it is a 16-bit
> microcontroller.

Did not.
I said "16-bit Intel 80C86". You can't be more "x86" than that. :)

Mateusz

Re: How to avoid an overflow during multiplication?

<rVGzJ.177608$Wkjc.152489@fx35.iad>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19732&group=comp.lang.c#19732

  copy link   Newsgroups: comp.lang.c
Path: i2pn2.org!i2pn.org!paganini.bofh.team!news.dns-netz.com!news.freedyn.de!newsfeed.xs4all.nl!newsfeed8.news.xs4all.nl!feeder1.feed.usenet.farm!feed.usenet.farm!peer02.ams4!peer.am4.highwinds-media.com!peer02.iad!feed-me.highwinds-media.com!news.highwinds-media.com!fx35.iad.POSTED!not-for-mail
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:91.0)
Gecko/20100101 Thunderbird/91.4.1
Subject: Re: How to avoid an overflow during multiplication?
Content-Language: en-US
Newsgroups: comp.lang.c
References: <sqmkg9$157v$1@gioia.aioe.org> <20211231062510.664@kylheku.com>
<sqn9ee$1utr$4@gioia.aioe.org>
From: Rich...@Damon-Family.org (Richard Damon)
In-Reply-To: <sqn9ee$1utr$4@gioia.aioe.org>
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Lines: 99
Message-ID: <rVGzJ.177608$Wkjc.152489@fx35.iad>
X-Complaints-To: abuse@easynews.com
Organization: Forte - www.forteinc.com
X-Complaints-Info: Please be sure to forward a copy of ALL headers otherwise we will be unable to process your complaint properly.
Date: Fri, 31 Dec 2021 12:16:09 -0500
X-Received-Bytes: 5035
 by: Richard Damon - Fri, 31 Dec 2021 17:16 UTC

On 12/31/21 11:00 AM, Mateusz Viste wrote:
> 2021-12-31 at 15:13 -0000, Kaz Kylheku wrote:
>> There is no timeunits parameter; is that ticks?
>
> Yes. I reworked the message a few times before posting to make it as
> clear as possible, and of course added mistakes along the way...
>
>> Ticks are often longer than a microsecond, so it can be
>> resonably expected that tempo / grouplen > 1.
>
> Actually, ticks are not a unit of time. Tempo is a unit of time
> (in MIDI terms it's the length, in microseconds, of a quarter note).
> Grouplen is the number of "ticks" (also called "unit time") in a quarter
> note (which is also called a "beat").
>
> But this does not matter anyway and I do not want to bore you to death.
> In any case you are correct that tempo is likely to be greater than
> grouplen, even though in theory it does not have to. Usually there's at
> least a 100:1 relation between tempo and grouplen.
>
>> E.g. a 1000 Hz timer interrupt produces 1000 us ticks. We multiply
>> by 1000 to go from ticks to seconds. If ticks can go to UINT32_MAX,
>> then we cannot go to microseconds in 32 bit.
>>
>> Therefore, this calculation has an inherent global overflow problem,
>> even if you address the local overflow in the multiplication.
>
> Nah, it works just fine. :)
>
> The end result is a number of microseconds that represents the
> delta-time of a MIDI note (that is "when will the next note occur").
> 2^32 microseconds is 71 minutes. I know no MIDI file that has such long
> pauses in between notes. Sure, one could craft such abomination, but it
> is not my ambition to cover such edge cases.
>
>> What you can do is right shift X and Y until you have enough headroom
>> for the multiplication:
>>
>> /* while the multiplication overflows, scale the fraction down */
>> while (ticks * tempo < ticks) {
>> ticks /= 2; /* compiles to a right shift */
>> grouplen /= 2;
>> }
>
> Yes, that would be a good solution, if there was no time constraints.
> The above loop is rich on branching and may lead to many
> multiplications... That's a lot of cycles (for a 4 MHz CPU).
>
>>> return ticks * (tempo / grouplen);
>>
>> If the fraction is greater than 1 but grouplen isn't a divisor of
>> tempo, it's can be horribly inaccurate.
>
> Yes, it is true. Fortunately in practice tempo is much higher than
> grouplen, so the practical accuracy of this computation on "normal"
> MIDI files is around 92-98%. Not perfect, but hard to hear. I then
> added my bit-shifting hack which bumped accuracy to 98-99% - but with
> some theoretical risk of introducing new overflows. Hence I was curious
> what other people do in similar circumstances.
>
>>> return ticks * (((tempo << 3) / grouplen) >> 3);
>>
>> So, if if a fixed shift works, you still want to do the multiplication
>> first, then division, for a better approximation.
>>
>> return ticks * (tempo / 8) / (grouplen / 8);
>
> I didn't thought of that, it's actually pretty neat - and
> straightforward, too! With the only risk being that the CPU will burn
> in flames if grouplen happens to be < 8 (but that's easy to check out of
> the critical loop since grouplen never changes).
>
>>> computations. It's also worth noting that "grouplen" is guaranteed
>>> to be a positive number that never changes across the calls of the
>>> function (which, in truth, is not even a function, but it was
>>> easier to format it as such for this exercise).
>>
>> OK, so then there may be a way to check somewhere else that the scaled
>> value grouplen / 8 is nonzero, to avoid division by zero, without
>> doing that for every calculation.
>
> Precisely, yes. I will do tests. Thank you for your input!
>
>
> Mateusz
>

One thought is that if tempo and grouplen don't change often, that you
could precompute an n and k such that

k = (tempo << n) / grouplen

and

MAX_TICKS * k

doesn't overflow.

Then you compute (ticks * k) >> n for your result.

Pages:12345678
server_pubkey.txt

rocksolid light 0.9.8
clearnet tor