Calculation with double precision

I’m working on an application that is critical for calculation precision.
I’m working with STM32F446XX processor, but I’m wondering if it can compute with double precision, if so, how can I make sure it computes with double precision.

yes, you can declare variables as double and you get computations with double floating point. The Cortex-M4 has a FPU, but only for singlec precision, so the math is done in software and you do not gain benefit of the FPU.
When you need double and speed, then you should use Cortex-M7.

I can see that even if I use double, the compiler chooses to use __aeabi_fmul instead of __aeabi_dmul, is it possible to force the compiler to use double multiplication instead?

that sounds strange, the compiler must choose the right instructions for the variables, and the Cortex-M libs definitely have double support, not like in the AVR 8 bit world.
I had more problems with the reverse case, that double is used because lots of libs don’t care between 42.0 and 42.0f constants, as explained here:

Especially on Cortex-M0 it wil blow your code size when the little ‘f’ is missing on contants or double is explicitly used.

A short piece of code for demonstration of the problem would be helpful, and which compiler and mbed-os version is used.


I checked code generation using double variable as test code below.

/* mbed Microcontroller Library
 * Copyright (c) 2019 ARM Limited
 * SPDX-License-Identifier: Apache-2.0

#include "mbed.h"

double dd = 1.234;

int main()
    double d;
    d = 0.000234;
    printf("double = %lf\n", dd*d);

Build the test program by Arm compiler:

mbed compile -m NUCLEO_F446RE -t ARM

Generated code by Arm compiler

        0x00000000:    b580        ..      PUSH     {r7,lr}
        0x00000002:    f2400000    @...    MOVW     r0,#:LOWER16: dd
        0x00000006:    f2c00000    ....    MOVT     r0,#:UPPER16: dd
        0x0000000a:    ed900b00    ....    VLDR     d0,[r0,#0]
        0x0000000e:    ed9f1b08    ....    VLDR     d1,[pc,#32] ; [0x30] = 0xb1cc9646
        0x00000012:    ec510b10    Q...    VMOV     r0,r1,d0
        0x00000016:    ec532b11    S..+    VMOV     r2,r3,d1
        0x0000001a:    f7fffffe    ....    BL       __aeabi_dmul
        0x0000001e:    4602        .F      MOV      r2,r0
        0x00000020:    a005        ..      ADR      r0,{pc}+0x18 ; 0x38
        0x00000022:    460b        .F      MOV      r3,r1
        0x00000024:    f7fffffe    ....    BL       __2printf
        0x00000028:    2000        .       MOVS     r0,#0
        0x0000002a:    bd80        ..      POP      {r7,pc}
        0x0000002c:    bf00        ..      NOP      
        0x0000002e:    bf00        ..      NOP      

Build the test program by GCC compiler:

mbed compile -m NUCLEO_F446RE -t GCC_ARM

Generated code by GCC

00000000 <main>:
   0:	4909      	ldr	r1, [pc, #36]	; (28 <main+0x28>)
   2:	b508      	push	{r3, lr}
   4:	e9d1 0100 	ldrd	r0, r1, [r1]
   8:	a305      	add	r3, pc, #20	; (adr r3, 20 <main+0x20>)
   a:	e9d3 2300 	ldrd	r2, r3, [r3]
   e:	f7ff fffe 	bl	0 <__aeabi_dmul>
  12:	4602      	mov	r2, r0
  14:	460b      	mov	r3, r1
  16:	4805      	ldr	r0, [pc, #20]	; (2c <main+0x2c>)
  18:	f7ff fffe 	bl	0 <printf>
  1c:	2000      	movs	r0, #0
  1e:	bd08      	pop	{r3, pc}
  20:	b1cc9646 	.word	0xb1cc9646
  24:	3f2eabbc 	.word	0x3f2eabbc

Both compiler generated __aeabi_dmul function call, so compiler generated double precision code.