• Skip to primary navigation
  • Skip to main content
  • Skip to footer

Codee

Automated code inspection for performance

  • Product
  • Use Cases
  • Resources
    • Catalog of best practice rules
    • Webinars
    • Blog
    • Releases
  • Company
    • About us
    • News
    • Careers
  • Request a demo

08/04/2021 Por Ivica Bogosavljević 1 Comment

Run your floating-point calculations with both precision and speed

One of our customers has a mathematical simulation program where precision matters. We were given the code for evaluation and asked to make it run faster. They have a strict requirement that the source code is compiled without any optimization flags that can influence precision. 

Run your floating-point calculations with both precision and speed

Most compilers offer a fast-math compiler flag that significantly improves performance at the expense of precision. It combines several types of optimizations that can be individually enabled using compiler flags. You don’t want to enable fast-math if precision is important to you, but there are some compiler flags that do not influence precision that will benefit the performance that you can enable. This post introduces the floating-point precision problem and presents an important compiler flag that increases performance without impacting precision.

The problem with floating-point numbers and precision

Compilers are really good at doing optimizations, but with floating-point calculations they need to be careful. Since floating-point numbers have a finite precision, some rules of algebra do not apply with floating-point numbers. For example, the law of associativity doesn’t hold in floating-point arithmetics, i.e.

(a + b) + c ≠ a + (b + c)

If a is 1030, b is -1030 and c is 1, the expression (a + b) + c gives 1, in contrast to expression a + (b + c) which gives 0 as the result [1].

To make floating-point calculations predictable and as precise as possible, IEEE 754 standard defines strict semantics. Strict IEEE 754 semantics disallow approximative instructions and optimizations using algebraic transformations that can influence the precision of the result. The goal is to make the calculations precise and predictable. Ideally, the same program compiled with different compilers should produce the same results if IEEE 754 strict semantics flag is enabled.

Compilers, when working with floating-points under IEEE 754 semantics, must be careful when doing optimizations, since a small change intended to increase the speed can result in your program outputting a slightly different result.

Most of the time, the difference in results due to compiler optimizations will be small. Because of this, all compilers provide an optimization flag that enables many floating-point optimizations that result in a faster code, but with no guarantees about the precision of the result, typically called fast-math compilation flag 1. This flag is -ffast-math for CLANG and GCC, -fp-model fast for Intel’s compiler, and /fp:fast for MSVC.

Code performance tips for your inbox. ✉ Subscribe

Compilation flag -ffast-math is not enabled by default in any optimization level. In most applications, you will want to enable it because it can yield a substantial performance boost. A gamer doesn’t care if the red component in a color of the shirt of the main character is off by one; he is really interested in a high frame rate.

However, there are some applications, mostly in the scientific domain, where small differences due to the loss of precision and rounding errors accumulate over time and can lead to incorrect results. Those programs will be typically compiled without the -ffast-math flag. The developers might decide to enable it if their program isn’t fast enough, but by enabling it they take the responsibility that the results produced by the program are still precise enough.

If you cannot enable -ffast-math because of the precision loss, there are other compiler flags that are part of -ffast-math but that do not affect precision and can be enabled independently.  In the next section we will talk about one such optimization.

Optimizing mathematical error detection and error management

Some floating-point operations can create invalid results. For example, division by zero is invalid, as is the square root of a negative number. The question is how to signal the bad values to the program so it can decide what to do next (stop the computation, or perform fixup operations) 2.

In C/C++, before IEEE 754 exceptions, floating-point errors were signaled through the errno variable defined in <errno.h>. This mechanism continues to be employed today and library mathematical functions, such as sqrt or log10, signal an error by writing the error code to the errno variable. Here is an example of code that exploits this fact:

errno = 0;
for (int i = 0; i < n; i++) {
    double result = sqrt(a[i]);
    if (errno == EDOM) {
        continue;
    }
    b[i] = result / n;
}

In the case the sqrt cannot compute the correct value (e.g. because the argument is negative), the computation is skipped.

From the performance perspective, setting errno costs some time, even when it is unused, since all library mathematical functions set it. Code that uses errno is also not optimal, especially in loops, since checking it requires a conditional statement and loops with conditional statements are more difficult for the compiler to efficiently optimize and vectorize.

Recommendations on performance and floating-point error management

Don’t use errno to check for floating-point errors. You can sanitize your inputs to make sure no function can receive bad arguments (eg. check that no zero denominator is used in divisions). Alternatively, you can rely on IEEE exceptions defined in fenv.h to let you know if your program is doing calculations on correct inputs, or, let the error propagate and simply check for NaNs or Infinities in the output result.

With default compiler flags, calls to mathematical functions like sqrt will get forwarded to slow library functions that set errno instead of fast hardware instructions. If your program doesn’t use errno to check for errors in the calculations, it is completely safe to disable it. It is done using the -fno-math-errno flag for GCC and CLANG.

We illustrate the performance difference with the following code snippet (click here for the full source code):

double rolling_average(double a[], int n) {
    double result = 0.0;

    for (int i = 0; i < n; i++) {
        result += sqrt(a[i]) / n;
    }

    return result;
}

In our measurements, using GCC 9.3, when we compiled the above code with and without -fno-math-errno, it took 497 ms to execute without -fno-math-errno and 128 ms to execute with -fno-math-errno. The result returned by the function was completely the same in both cases. In this particular example, flag -fno-math-errno allowed the loop to be vectorized, which explains the performance improvement3.

Don’t miss our next blog post. ✉ Subscribe!

This flag should be enabled whenever the performance of mathematical functions is important. The speed improvement will depend on the loop, compiler, etc, but generally, you should expect performance increase. 

Summary

Most code bases can increase their performance by enabling the -ffast-math (or equivalent) compiler switch to allow faster computations and the expense of some precision loss. The flag -ffast-math automatically enables several compiler flags related to mathematical operations optimization. One of those flags is -fno-math-errno, which can also be enabled without using -ffast-math. For code bases that require the maximum precision possible, using this flag is a good idea. Enabling it will bring a performance boost by allowing the compiler to use fast instructions instead of slow library calls, with zero impact on precision.

In the next post, we will go deeper into precision and vectorization, specifically, how you can speed up parts of your code if you are willing to give up on a bit of precision in your hot loops.

Building performance into the code from day one with Codee

Request a demo
Contact our team

References

[1] What Every Computer Scientist Should Know About Floating-Point Arithmetic
[2] GCC Wiki – Floating Point Math
[3] Linux Programmer’s Manual – Math Error
[4] CLANG Vectorizer Documentation
[5] LIBC – Errors in Floating-Point Calculations
[6] Microsoft Visual C++ – errno, _doserrno, _sys_errlist, and _sys_nerr


1 With -ffast-math, the compiler can do many optimizations, roughly divided into three groups: (1) optimizations arising from rules of arithmetics (e.g. (-a) * (-b) = a * b); (2) optimizations arising from using approximate instructions, e.g. a / b = a * (1 / b), where expression (1 / b) is calculated using approximate reciprocal division instruction which is much faster than the regular division and (3) optimizations related to floating-point error management. These optimizations open door to other optimizations like common subexpression elimination, loop invariant code motion, vectorization, etc.

2 More information about floating-point error handling can be found in LIBC manual.

3 Please note that this improvement happened on a very short example using a specific compiler. The amount of improvement will depend on the compiler and loop source code, but generally, with a project which is large enough, you should definitely expect performance improvements with `-fno-math-errno` on all compilers.

Filed Under: Technical Tagged With: code performance, errno, error management, fast-math, floating-point, floating-point arithmetics, optimization, precision, speed

Previous Post
Next Post

Reader Interactions

Comments

  1. P says

    07/01/2022 at 03:26

    Excellent article. To the point without getting too technical about IEEE etc. I’ll be trying it today

    Thx

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Footer

PRODUCT

Request a demo

Purchase inquiry

Knowledge base

COMPANY

About us

Become a partner

Contact us

Newsletter

FOLLOW US

  • LinkedIn
  • Twitter
  • YouTube

NEWSLETTER

Cambiar | Eliminar

APPENTRA SOLUTIONS S.L
P.º Marítimo, 22b, 15679 Cambre, A Coruña, Spain

Cookie Policy | Privacy policy | Legal Disclaimer

Copyright © 2023 Appentra Solutions, S.L.

We use cookies!
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish.
Accept Cookies Read more
Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. these cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your experience.

CookieTypeDurationDescription
0
__asc030 minutes
__auc01 year
__bs_id01 year
__cfduid11 monthThe cookie is set by CloudFare. The cookie is used to identify individual clients behind a shared IP address d apply security settings on a per-client basis. It doesnot correspond to any user ID in the web application and does not store any personally identifiable information.
__gads01 yearThis cookie is set by Google and stored under the name dounleclick.com. This cookie is used to track how many times users see a particular advert which helps in measuring the success of the campaign and calculate the revenue generated by the campaign. These cookies can only be read from the domain that it is set on so it will not track any data while browsing through another sites.
__lxGr__ses015 minutes
__lxGr__var_654116015 minutes
__lxGr__var_654122015 minutes
__lxGr__var_654124015 minutes
__lxGr__var_654130015 minutes
__lxGr__var_654134015 minutes
__lxGr__var_654146015 minutes
__lxGr__var_654157015 minutes
__lxGr__var_654161015 minutes
__lxGr__var_654163015 minutes
__lxGr__var_654165015 minutes
__lxGr__var_654333015 minutes
__stid01 yearThe cookie is set by ShareThis. The cookie is used for site analytics to determine the pages visited, the amount of time spent, etc.
__stidv01 year
__utma02 yearsThis cookie is set by Google Analytics and is used to distinguish users and sessions. The cookie is created when the JavaScript library executes and there are no existing __utma cookies. The cookie is updated every time data is sent to Google Analytics.
__utmb030 minutesThe cookie is set by Google Analytics. The cookie is used to determine new sessions/visits. The cookie is created when the JavaScript library executes and there are no existing __utma cookies. The cookie is updated every time data is sent to Google Analytics.
__utmc0The cookie is set by Google Analytics and is deleted when the user closes the browser. The cookie is not used by ga.js. The cookie is used to enable interoperability with urchin.js which is an older version of Google analytics and used in conjunction with the __utmb cookie to determine new sessions/visits.
__utmt010 minutesThe cookie is set by Google Analytics and is used to throttle the request rate.
__utmt_onm010 minutes
__utmz06 monthsThis cookie is set by Google analytics and is used to store the traffic source or campaign through which the visitor reached your site.
_abck01 year
_cb01 year
_cb_ls01 year
_cb_svref030 minutes
_chartbeat201 year
_fbp02 monthsThis cookie is set by Facebook to deliver advertisement when they are on Facebook or a digital platform powered by Facebook advertising after visiting this website.
_ga02 yearsThis cookie is installed by Google Analytics. The cookie is used to calculate visitor, session, camapign data and keep track of site usage for the site's analytics report. The cookies store information anonymously and assigns a randoly generated number to identify unique visitors.
_ga_Y5Q8GRTQY902 years
_gat01 minuteThis cookies is installed by Google Universal Analytics to throttle the request rate to limit the colllection of data on high traffic sites.
_gat_bgs01 minute
_gat_gtag_UA_25587466_801 minuteGoogle uses this cookie to distinguish users.
_gat_gtag_UA_84471197_1601 minuteGoogle uses this cookie to distinguish users.
_gat_hearst01 minute
_gat_tDelegDominio01 minute
_gat_tDominio01 minute
_gat_tRollupComscore01 minute
_gat_tRollupDelegacion01 minute
_gat_tRollupGlobal01 minute
_gat_tRollupLvgTotal01 minute
_gat_tRollupNivel101 minute
_gat_UA-5144860-201 minuteThis is a pattern type cookie set by Google Analytics, where the pattern element on the name contains the unique identity number of the account or website it relates to. It appears to be a variation of the _gat cookie which is used to limit the amount of data recorded by Google on high traffic volume websites.
_gid01 dayThis cookie is installed by Google Analytics. The cookie is used to store information of how visitors use a website and helps in creating an analytics report of how the wbsite is doing. The data collected including the number visitors, the source where they have come from, and the pages viisted in an anonymous form.
_kuid_05 monthsThe cookie is set by Krux Digital under the domain krxd.net. The cookie stores a unique ID to identify a returning user for the purpose of targeted advertising.
_li_ss01 month
Necessary
Always Enabled

Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.

CookieTypeDurationDescription
__cfduid11 monthThe cookie is set by CloudFare. The cookie is used to identify individual clients behind a shared IP address d apply security settings on a per-client basis. It doesnot correspond to any user ID in the web application and does not store any personally identifiable information.
cookielawinfo-checkbox-necessary011 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-necessary01 hourThis cookie is set by GDPR Cookie Consent plugin. The purpose of this cookie is to check whether or not the user has given the consent to the usage of cookies under the category 'Necessary'.
cookielawinfo-checkbox-non-necessary011 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Non Necessary".
cookielawinfo-checkbox-non-necessary01 hourThis cookie is set by GDPR Cookie Consent plugin. The purpose of this cookie is to check whether or not the user has given their consent to the usage of cookies under the category 'Non-Necessary'.
DSID11 hourTo note specific user identity. Contains hashed/encrypted unique ID.
JSESSIONID1Used by sites written in JSP. General purpose platform session cookies that are used to maintain users' state across page requests.
PHPSESSID0This cookie is native to PHP applications. The cookie is used to store and identify a users' unique session ID for the purpose of managing user session on the website. The cookie is a session cookies and is deleted when all the browser windows are closed.
pmpro_visit0The cookie is set by the Paid Membership Pro plugin. The cookie is used to manage user memberships.
viewed_cookie_policy011 monthsThe cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
viewed_cookie_policy01 hourThe cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Analytics

Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.

CookieTypeDurationDescription
__gads01 yearThis cookie is set by Google and stored under the name dounleclick.com. This cookie is used to track how many times users see a particular advert which helps in measuring the success of the campaign and calculate the revenue generated by the campaign. These cookies can only be read from the domain that it is set on so it will not track any data while browsing through another sites.
__stid01 yearThe cookie is set by ShareThis. The cookie is used for site analytics to determine the pages visited, the amount of time spent, etc.
_ga02 yearsThis cookie is installed by Google Analytics. The cookie is used to calculate visitor, session, camapign data and keep track of site usage for the site's analytics report. The cookies store information anonymously and assigns a randoly generated number to identify unique visitors.
_gat_gtag_UA_25587466_801 minuteGoogle uses this cookie to distinguish users.
_gat_gtag_UA_84471197_1601 minuteGoogle uses this cookie to distinguish users.
_gid01 dayThis cookie is installed by Google Analytics. The cookie is used to store information of how visitors use a website and helps in creating an analytics report of how the wbsite is doing. The data collected including the number visitors, the source where they have come from, and the pages viisted in an anonymous form.
ad-id17 monthsProvided by amazon-adsystem.com for tracking user actions on other websites to provide targeted content
demdex05 monthsThis cookie is set under the domain demdex.net and is used by Adobe Audience Manager to help identify a unique visitor across domains.
GPS030 minutesThis cookie is set by Youtube and registers a unique ID for tracking users based on their geographical location
pardot0The cookie is set when the visitor is logged in as a Pardot user.
tk_lr01 yearThis cookie is set by JetPack plugin on sites using WooCommerce. This is a referral cookie used for analyzing referrer behavior for Jetpack
tk_or05 yearsThis cookie is set by JetPack plugin on sites using WooCommerce. This is a referral cookie used for analyzing referrer behavior for Jetpack
tk_r3d03 daysThe cookie is installed by JetPack. Used for the internal metrics fo user activities to improve user experience
Advertisement

Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.

CookieTypeDurationDescription
_fbp02 monthsThis cookie is set by Facebook to deliver advertisement when they are on Facebook or a digital platform powered by Facebook advertising after visiting this website.
_kuid_05 monthsThe cookie is set by Krux Digital under the domain krxd.net. The cookie stores a unique ID to identify a returning user for the purpose of targeted advertising.
ad-privacy15 yearsProvided by amazon-adsystem.com for tracking user actions on other websites to provide targeted content to the users.
ATN12 yearsThe cookie is set by atdmt.com. The cookies stores data about the user behavior on multiple websites. The data is then used to serve relevant advertisements to the users on the website.
dpm05 monthsThe cookie is set by demdex.net. This cookie assigns a unique ID to each visiting user that allows third-party advertisers target that users with relevant ads.
everest_g_v201 yearThe cookie is set under eversttech.net domain. The purpose of the cookie is to map clicks to other events on the client's website.
fr12 monthsThe cookie is set by Facebook to show relevant advertisments to the users and measure and improve the advertisements. The cookie also tracks the behavior of the user across the web on sites that have Facebook pixel or Facebook social plugin.
IDE12 yearsUsed by Google DoubleClick and stores information about how the user uses the website and any other advertisement before visiting the website. This is used to present users with ads that are relevant to them according to the user profile.
khaos01 yearThis cookie is set by rubiconproject.com. The cookie is used to store user data in an anonymous form such as the IP address, geographical location, websites visited, and the ads clicked. The purpose of the cookie is to tailor the ads displayed to the users based on the users movement on other site in the same ad network.
ljt_reader01 yearThis is a Lijit Advertising Platform cookie. The cookie is used for recognizing the browser or device when users return to their site or one of their partner's site.
mako_uid01 yearThis cookie is set under the domain ps.eyeota.net. The cookies is used to collect data about the users' visit to the website such as the pages visited. The data is used to create a users' profile in terms of their interest and demographic. This data is used for targeted advertising and marketing.
mc01 yearThis cookie is associated with Quantserve to track anonymously how a user interact with the website.
NID16 monthsThis cookie is used to a profile based on user's interest and display personalized ads to the users.
p201 weekThe cookies is set by ownerIQ for the purpose of providing relevant advertisement.
personalization_id02 yearsThis cookie is set by twitter.com. It is used integrate the sharing features of this social media. It also stores information about how the user uses the website for tracking and targeting.
PUBMDCID02 monthsThis cookie is set by pubmatic.com. The cookie stores an ID that is used to display ads on the users' browser.
si05 yearsThe cookies is set by ownerIQ for the purpose of providing relevant advertisement.
TDCPM01 yearThe cookie is set by CloudFare service to store a unique ID to identify a returning users device which then is used for targeted advertising.
TDID01 yearThe cookie is set by CloudFare service to store a unique ID to identify a returning users device which then is used for targeted advertising.
test_cookie015 minutesThis cookie is set by doubleclick.net. The purpose of the cookie is to determine if the users' browser supports cookies.
tuuid01 yearThis cookie is set by .bidswitch.net. The cookies stores a unique ID for the purpose of the determining what adverts the users have seen if you have visited any of the advertisers website. The information is used for determining when and how often users will see a certain banner.
tuuid_lu01 yearThis cookie is set by .bidswitch.net. The cookies stores a unique ID for the purpose of the determining what adverts the users have seen if you have visited any of the advertisers website. The information is used for determining when and how often users will see a certain banner.
uid01 monthThis cookie is used to measure the number and behavior of the visitors to the website anonymously. The data includes the number of visits, average duration of the visit on the website, pages visited, etc. for the purpose of better understanding user preferences for targeted advertisments.
uuid01 monthTo optimize ad relevance by collecting visitor data from multiple websites such as what pages have been loaded.
VISITOR_INFO1_LIVE15 monthsThis cookie is set by Youtube. Used to track the information of the embedded YouTube videos on a website.
Technical

Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.

CookieTypeDurationDescription
__utma02 yearsThis cookie is set by Google Analytics and is used to distinguish users and sessions. The cookie is created when the JavaScript library executes and there are no existing __utma cookies. The cookie is updated every time data is sent to Google Analytics.
__utmb030 minutesThe cookie is set by Google Analytics. The cookie is used to determine new sessions/visits. The cookie is created when the JavaScript library executes and there are no existing __utma cookies. The cookie is updated every time data is sent to Google Analytics.
__utmc0The cookie is set by Google Analytics and is deleted when the user closes the browser. The cookie is not used by ga.js. The cookie is used to enable interoperability with urchin.js which is an older version of Google analytics and used in conjunction with the __utmb cookie to determine new sessions/visits.
__utmt010 minutesThe cookie is set by Google Analytics and is used to throttle the request rate.
__utmz06 monthsThis cookie is set by Google analytics and is used to store the traffic source or campaign through which the visitor reached your site.
_gat01 minuteThis cookies is installed by Google Universal Analytics to throttle the request rate to limit the colllection of data on high traffic sites.
_gat_UA-5144860-201 minuteThis is a pattern type cookie set by Google Analytics, where the pattern element on the name contains the unique identity number of the account or website it relates to. It appears to be a variation of the _gat cookie which is used to limit the amount of data recorded by Google on high traffic volume websites.
AMP_TOKEN01 hourThis cookie is set by Google Analytics - This cookie contains a token that can be used to retrieve a Client ID from AMP Client ID service. Other possible values indicate opt-out, inflight request or an error retrieving a Client ID from AMP Client ID service.
audit01 yearThis cookie is set by Rubicon Project and is used for recording cookie consent data.
bcookie02 yearsThis cookie is set by linkedIn. The purpose of the cookie is to enable LinkedIn functionalities on the page.
lang0This cookie is used to store the language preferences of a user to serve up content in that stored language the next time user visit the website.
lidc01 dayThis cookie is set by LinkedIn and used for routing.
mailchimp_landing_site04 weeksThe cookie is set by the email marketing service MailChimp.
na_id01 yearThis cookie is set by Addthis.com to enable sharing of links on social media platforms like Facebook and Twitter
ouid01 yearThe cookie is set by Addthis which enables the content of the website to be shared across different networking and social sharing websites.
pid01 yearHelps users identify the users and lets the users use twitter related features from the webpage they are visiting.
PugT01 monthThis cookie is set by pubmatic.com. The purpose of the cookie is to check when the cookies were last updated on the browser in order to limit the number of calls to the server-side cookie store.
sid0This cookie is very common and is used for session state management.
test_cookie011 monthsThis cookie is set by doubleclick.net. The purpose of the cookie is to determine if the users' browser supports cookies.
YSC1This cookies is set by Youtube and is used to track the views of embedded videos.
Save & Accept
X