Deutsch English Français Italiano |
<vrvp94$3q1ah$1@paganini.bofh.team> View for Bookmarking (what is this?) Look up another Usenet article |
Path: news.eternal-september.org!eternal-september.org!feeder3.eternal-september.org!newsfeed.bofh.team!paganini.bofh.team!not-for-mail From: antispam@fricas.org (Waldek Hebisch) Newsgroups: comp.lang.c Subject: Re: Fast division (was Re: Suggested method for returning a string from a C program?) Date: Wed, 26 Mar 2025 02:37:26 -0000 (UTC) Organization: To protect and to server Message-ID: <vrvp94$3q1ah$1@paganini.bofh.team> References: <vrd77d$3nvtf$2@dont-email.me> <20250319115550.0000676f@yahoo.com> <vreuj1$1asii$4@dont-email.me> <vreve4$19klp$2@dont-email.me> <20250319201903.00005452@yahoo.com> <86r02roqdq.fsf@linuxsc.com> <vrh1br$35029$2@dont-email.me> <LRUCP.2$541.0@fx47.iad> <vrh71t$3be42$1@dont-email.me> <vrk8vm$2f4gc$1@paganini.bofh.team> <20250321113316.506@kylheku.com> <vrl6hp$2qg20$1@dont-email.me> <20250321210228.508@kylheku.com> <vrmg7d$2nif7$2@paganini.bofh.team> <vrvjr9$i7gg$1@dont-email.me> Injection-Date: Wed, 26 Mar 2025 02:37:26 -0000 (UTC) Injection-Info: paganini.bofh.team; logging-data="3999057"; posting-host="WwiNTD3IIceGeoS5hCc4+A.user.paganini.bofh.team"; mail-complaints-to="usenet@bofh.team"; posting-account="9dIQLXBM7WM9KzA+yjdR4A"; User-Agent: tin/2.6.2-20221225 ("Pittyvaich") (Linux/6.1.0-9-amd64 (x86_64)) X-Notice: Filtered by postfilter v. 0.9.3 Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote: > On 22.03.2025 15:07, Waldek Hebisch wrote: >> >> Actually, to do fast division of N-bit number by fixed N-bit number >> one need 2N-bit multiplication. > > I just stumbled across your post and above sentence. Do you mean *one* > multiplication of 2N bit numbers? - Could you please explain that (by > an example, or could you provide a reference)? One multiplications with 2N bit result + few other operations like shifts and additions. Consider for example: unsigned int divv(unsigned int a) { return a/1234567; } My gcc-12 at -O generates the following assembly code: divv: ..LFB0: .cfi_startproc movl %edi, %eax movl $3000869427, %edx imulq %rdx, %rax shrq $32, %rax subl %eax, %edi shrl %edi addl %edi, %eax shrl $20, %eax ret So 1 multiplication, 3 shifts, subtraction and addtion. When more bits of multiplication are available one can use smaller number of extra operations. For example, when I change function above so that argument is 16-bit and divisor is 12345, the code is: divv: ..LFB0: .cfi_startproc movzwl %di, %eax imull $43489, %eax, %eax shrl $29, %eax ret So just 1 multiplication and 1 shift. The idea beside this is quite simple: instead of division we multiply by reciprocal. Reciprocal is represented in fixed point aritihemtic (so normally there is at least one shift to get binary point in right place). Since divisor is fixed reciprocal can be precomputed. This works best when there is enough accuracy, otherwise one needs to add extra steps. Working out how many bits of accuracy are needed is a bit tricky, in particular by adding extra operations one can lower needed accuracy. > (The reason for my question is that for integer divisions of length N > an old DSP I used required besides shifts effectively N subtractions > to create the result and modulus; it didn't use any multiplications.) Method above is good when you have fast and wide multiplier (compared to your numbers). Also there is cost of precomputation, to gain divisor must be fixed or at least change slowly. If you have varying divisor then one can use Newton method (IIUC this is what modern CPU-s use). Shifts and subtractions are good when you do not have fast multiplier. -- Waldek Hebisch