Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #121694 > unrolled thread

a MSVC and glibc-compatible fmod()

Started byBonita Montero <Bonita.Montero@gmail.com>
First post2025-02-24 11:48 +0100
Last post2025-03-09 14:56 +0200
Articles 20 on this page of 134 — 8 participants

Back to article view | Back to comp.lang.c++


Contents

  a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-24 11:48 +0100
    Re: a MSVC and glibc-compatible fmod() Muttley@DastardlyHQ.org - 2025-02-24 12:00 +0000
      Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-24 13:48 +0100
        Re: a MSVC and glibc-compatible fmod() Muttley@DastardlyHQ.org - 2025-02-24 13:09 +0000
          Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-24 14:22 +0100
            Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-24 17:13 +0200
              Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-24 16:19 +0100
                Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-24 17:52 +0200
                  Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-25 09:09 +0100
                    Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-25 16:17 +0100
                    Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-25 17:26 +0200
                      Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-25 16:45 +0100
                        Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-25 16:57 +0100
                        Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-25 19:17 +0200
                          Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-25 18:58 +0100
                            Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-26 00:36 +0200
                              Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-26 04:15 +0100
                              Re: a MSVC and glibc-compatible fmod() Muttley@DastardlyHQ.org - 2025-02-26 08:16 +0000
                                Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-26 14:27 +0200
                                  Re: a MSVC and glibc-compatible fmod() Muttley@DastardlyHQ.org - 2025-02-26 14:39 +0000
                                    FP_CONTRACT was : a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-28 16:28 +0200
                                      Re: FP_CONTRACT was : a MSVC and glibc-compatible fmod() Tim Rentsch <tr.17687@z991.linuxsc.com> - 2025-03-01 08:35 -0800
          Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-24 16:22 +0200
            Re: a MSVC and glibc-compatible fmod() Muttley@DastardlyHQ.org - 2025-02-24 15:10 +0000
              Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-24 17:33 +0200
                Re: a MSVC and glibc-compatible fmod() Muttley@DastardlyHQ.org - 2025-02-24 16:48 +0000
    Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-02-24 22:21 +0000
      Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-25 07:37 +0100
        Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-02-25 23:03 +0000
          Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-26 02:00 +0200
          Re: a MSVC and glibc-compatible fmod() Wuns Haerst <Wuns.Haerst@wurstfabrik.at> - 2025-02-26 04:01 +0100
      Re: a MSVC and glibc-compatible fmod() Muttley@DastardlyHQ.org - 2025-02-25 08:24 +0000
    Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-02-27 21:16 +0000
      Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-28 07:59 +0100
      Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-02-28 12:35 +0200
        Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-02-28 18:12 +0000
      Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-28 19:23 +0100
    Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-02-28 18:30 +0000
      Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-28 19:31 +0100
        Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-02-28 19:47 +0000
          Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-02-28 20:49 +0100
            Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-03-01 14:37 +0000
              Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-01 16:58 +0100
                Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-03-01 17:11 +0000
                  Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-01 21:02 +0100
                    Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-03-01 20:32 +0000
                      Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-01 21:37 +0100
                        Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-03-01 20:45 +0000
                  Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 09:40 +0100
    Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-01 22:55 +0200
      Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-02 18:54 +0200
        Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 17:59 +0100
    Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-02 15:41 +0200
      Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 17:10 +0100
        Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-03-02 16:22 +0000
          Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 17:26 +0100
            Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-02 19:07 +0200
              Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 18:09 +0100
                Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 18:11 +0100
                  Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-02 19:52 +0200
                    Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 18:55 +0100
                      Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-02 20:09 +0200
                        Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 19:14 +0100
                        Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 19:57 +0100
                          Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-02 22:58 +0200
                            Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-03 12:52 +0100
                              Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-03 18:10 +0200
                                Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-03 23:55 +0200
                                Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-07 09:51 +0100
                          Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-03 18:20 +0200
                            Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-03 17:30 +0100
                              Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-03 19:27 +0200
                                Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-03 18:39 +0100
                      Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-03 02:01 +0200
          Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-02 19:37 +0200
            Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 18:41 +0100
              Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-02 20:00 +0200
                Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-02 19:01 +0100
        Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-09 01:31 +0200
          Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 07:41 +0100
            Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-09 11:08 +0200
              Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 10:31 +0100
                Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-09 11:46 +0200
                  Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 10:54 +0100
                    Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-09 12:09 +0200
                      Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 11:21 +0100
                        Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-09 14:09 +0200
                          Re: a MSVC and glibc-compatible fmod() Mr Flibble <leigh@i42.co.uk> - 2025-03-09 15:26 +0000
                            Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 17:02 +0100
                              Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-09 19:55 +0200
                                Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 19:10 +0100
                                  Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 19:27 +0100
                          Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 17:23 +0100
                            Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-09 20:04 +0200
                              Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 19:11 +0100
                                Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 20:11 +0100
                              Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 07:24 +0100
                                Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 10:46 +0100
                                  Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-10 14:26 +0200
                                    Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 13:45 +0100
                                      Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-10 16:33 +0200
                                        Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 15:46 +0100
                                          Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-10 16:59 +0200
                                            Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 16:11 +0100
                                              Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-10 17:43 +0200
                                                Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 17:13 +0100
                                                  Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-10 19:51 +0200
                                                    Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 19:00 +0100
                                                      Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-10 20:38 +0200
                                                        Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 22:34 +0100
                                                          Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 22:36 +0100
                                                            Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-11 12:47 +0200
                                                        Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 23:52 +0100
                                                          Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 23:57 +0100
                                                            Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-11 09:34 +0100
                                                              Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-11 12:29 +0200
                                                                Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-11 12:12 +0100
                                                                  Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-11 13:34 +0200
                                                                    Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-11 13:10 +0100
                                                                      Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-11 14:55 +0200
                                                                        Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-11 14:08 +0100
                                                                        Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-11 15:46 +0200
                                                                  Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-11 13:51 +0200
                                                                Re: a MSVC and glibc-compatible fmod() James Kuyper <jameskuyper@alumni.caltech.edu> - 2025-03-11 14:21 -0400
                                                        Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-11 20:28 +0200
                                                          Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-16 13:48 +0200
                                Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-10 13:17 +0200
                                  Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 12:53 +0100
                                  Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-10 12:54 +0100
                Re: a MSVC and glibc-compatible fmod() wij <wyniijj5@gmail.com> - 2025-03-09 18:51 +0800
                  Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 12:56 +0100
                    Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-09 14:23 +0200
                      Re: a MSVC and glibc-compatible fmod() Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-09 13:39 +0100
                        Re: a MSVC and glibc-compatible fmod() Michael S <already5chosen@yahoo.com> - 2025-03-09 14:56 +0200

Page 5 of 7 — ← Prev page 1 2 3 4 [5] 6 7  Next page →


#121903

FromMichael S <already5chosen@yahoo.com>
Date2025-03-09 11:08 +0200
Message-ID<20250309110801.0000131a@yahoo.com>
In reply to#121902
On Sun, 9 Mar 2025 07:41:26 +0100
Bonita Montero <Bonita.Montero@gmail.com> wrote:

> Am 09.03.2025 um 00:31 schrieb Michael S:
> > This code does not work in plenty of cases. It seems, your test
> > vectors have poor coverage.
> > Try, for example, x=1.8037919852882307, y=2.22605637008665934e-194  
> 
> 	cout << hexfloat << myFmod( 1.8037919852882307, 
> 2.22605637008665934e-194 ) << endl;
> 	cout << hexfloat << fmod( 1.8037919852882307,
> 2.22605637008665934e-194 ) << endl;
> 
> 
> Prints the same result under Linux and Windows.
> 

What it prints under Linux is irrelevant. Under Linux it compiles your
original version or its close equivalent that is slow, ugly, but not
buggy.
What it prints under Windows when compiled with clang or gcc is also
irrelevant for the same reason. 
The bug is in the new code that is exposed only when compiled with MSVC
compiler.

-- foo.cpp
#include <cstdint>
#include <cassert>
#include <cfenv>
#include <limits>
#include <bit>
using namespace std;

template<bool _32 = false>
double xMyFmod( double x, double y )
{
	constexpr uint64_t
		SIGN = 1ull << 63,
		IMPLICIT = 1ull << 52,
		MANT = IMPLICIT - 1,
		QBIT = 1ull << 51;
	uint64_t const
		binX = bit_cast<uint64_t>( x ),
		binY = bit_cast<uint64_t>( y );
	static auto abs = []( uint64_t m ) { return m & ~SIGN; };
	auto isNaN = []( uint64_t m ) { return abs( m ) >=
0x7FF0000000000001u; }; auto isSig = []( uint64_t m ) { return !(m &
QBIT); }; if( isNaN( binX ) ) [[unlikely]] // x == NaN
#if defined(_MSC_VER)
		return bit_cast<double>( isNaN( binY ) ? binY | binX &
binY & QBIT : binX );
#else
	{
		if( isSig( binX ) || isNaN( binY ) && isSig( binY ) )
[[unlikely]] feraiseexcept( FE_INVALID );
		return bit_cast<double>( binX | QBIT );
	}
#endif
	auto isInf = []( uint64_t m ) { return abs( m ) ==
0x7FF0000000000000u; }; if( isNaN( binY ) ) [[unlikely]] // x != NaN ||
y == NaN #if defined(_MSC_VER)
	{
		if constexpr( _32 )
			if( isInf( binX ) )
				feraiseexcept( FE_INVALID );
		return y;
	}
#else
	{
		if( isSig( binY ) ) [[unlikely]]
			feraiseexcept( FE_INVALID );
		return bit_cast<double>( binY | QBIT );
	}
#endif
	if( isInf( binX ) ) // x == Inf
	{
		feraiseexcept( FE_INVALID );
#if defined(_MSC_VER)
		return bit_cast<double>( binX & ~MANT | QBIT );
#else
		return -numeric_limits<double>::quiet_NaN();
#endif
	}
	if( !abs( binY ) ) [[unlikely]] // y == 0
	{
		feraiseexcept( FE_INVALID );
#if defined(_MSC_VER)
		return numeric_limits<double>::quiet_NaN();
#else
		return -numeric_limits<double>::quiet_NaN();
#endif
	}
	if( !abs( binX ) || isInf( binY ) ) [[unlikely]] // x == 0 || y
== Inf return x;
	auto exp = []( uint64_t b ) -> int { return b >> 52 & 0x7FF; };
	int
		expX = exp( binX ),
		expY = exp( binY );
	auto mant = []( uint64_t b ) { return b & MANT; };
	uint64_t
		mantX = mant( binX ),
		mantY = mant( binY );
	int headBits = 11;
	static auto normalize = [&]( int &exp, uint64_t &mant )
	{
		unsigned shift = countl_zero( mant ) - headBits;
		mant <<= shift;
		exp -= shift;
	};
	auto build = []( int &exp, uint64_t &mant )
	{
		if( exp ) [[likely]]
			mant |= IMPLICIT;
		else
		{
			exp = 1;
			normalize( exp, mant );
		}
	};
	build( expX, mantX );
	build( expY, mantY );
	int
		tailX = countr_zero( mantX ),
		tailY = countr_zero( mantY ),
		tailBits = tailX <= tailY ? tailX : tailY;
	headBits += tailBits;
	mantX >>= tailBits;
	mantY >>= tailBits;
	uint64_t signX = binX & SIGN;
	int expDiff;
#if defined(_MSC_VER)
	while( (expDiff = expX - expY) > 63 )
	{
		unsigned long long hi = mantX >> 1, lo = mantX << 63,
remainder; (void)_udiv128( hi, lo, mantY, &remainder );
		expX -= 63;
		mantX = remainder;
		normalize( expX, mantX );
	}
#endif
	while( (expDiff = expX - expY) > 0 )
	{
		unsigned bits = expDiff <= headBits ? expDiff :
headBits; if( !(mantX = (mantX << bits) % mantY) ) [[unlikely]]
			return bit_cast<double>( signX );
		expX -= bits;
		normalize( expX, mantX );
	}
	if( !expDiff && mantX >= mantY ) [[unlikely]]
		if( (mantX -= mantY) ) [[likely]]
			normalize( expX, mantX );
		else
			return bit_cast<double>( signX );
	mantX <<= tailBits;
	mantY <<= tailBits;
	if( expX <= 0 ) [[unlikely]]
	{
		assert(expX >= -51);
		mantX = mantX >> (unsigned)(-expX + 1);
		expX = 0;
	}
	return bit_cast<double>( signX | (uint64_t)expX << 52 | mantX &
MANT ); }

double myFmod( double x, double y )
{
	return xMyFmod( x, y );
}

inline float myFmod( float x, float y )
{
	return (float)xMyFmod<true>( (double)x, (double)y );
}

-- end of foo.cpp


-- bar.cpp
#include <iostream>
using namespace std;

double myFmod( double x, double y );

int main()
{
	cout << hexfloat << myFmod(
		1.8037919852882307,
		2.22605637008665934e-194 ) << endl;
	cout << hexfloat << fmod( 1.8037919852882307,
		2.22605637008665934e-194 ) << endl;
}

-- end of foo.cpp


W:\foobar>cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.41.34120 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]


W:\foobar>cl -nologo -O2 -EHsc -std:c++20 foo.cpp bar.cpp
foo.cpp
bar.cpp
Generating Code...

W:\foobar>foo
0x1.0000000000000p-696
0x0.0000000000000p+0

[toc] | [prev] | [next] | [standalone]


#121904

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-09 10:31 +0100
Message-ID<vqjn4h$lmd1$1@raubtier-asyl.eternal-september.org>
In reply to#121903
This prints the same result (0.0) under Windows and Linux:

double myFmod( double x, double y )
{
	constexpr uint64_t
		SIGN = 1ull << 63,
		IMPLICIT = 1ull << 52,
		MANT = IMPLICIT - 1,
		QBIT = 1ull << 51;
	uint64_t const
		binX = bit_cast<uint64_t>( x ),
		binY = bit_cast<uint64_t>( y );
	static auto abs = []( uint64_t m ) { return m & ~SIGN; };
	auto isNaN = []( uint64_t m ) { return abs( m ) >= 0x7FF0000000000001u; };
	auto isSig = []( uint64_t m ) { return !(m & QBIT); };
	if( isNaN( binX ) ) [[unlikely]] // x == NaN
#if defined(_MSC_VER)
		return bit_cast<double>( isNaN( binY ) ? binY | binX & binY & QBIT : 
binX );
#else
	{
		if( isSig( binX ) || isNaN( binY ) && isSig( binY ) ) [[unlikely]]
			feraiseexcept( FE_INVALID );
		return bit_cast<double>( binX | QBIT );
	}
#endif
	if( isNaN( binY ) ) [[unlikely]] // x != NaN || y == NaN
#if defined(_MSC_VER)
		return y;
#else
	{
		if( isSig( binY ) ) [[unlikely]]
			feraiseexcept( FE_INVALID );
		return bit_cast<double>( binY | QBIT );
	}
#endif
	auto isInf = []( uint64_t m ) { return abs( m ) == 0x7FF0000000000000u; };
	if( isInf( binX ) ) // x == Inf
	{
		feraiseexcept( FE_INVALID );
#if defined(_MSC_VER)
		return bit_cast<double>( binX & ~MANT | QBIT );
#else
		return -numeric_limits<double>::quiet_NaN();
#endif
	}
	if( !abs( binY ) ) [[unlikely]] // y == 0
	{
		feraiseexcept( FE_INVALID );
#if defined(_MSC_VER)
		return numeric_limits<double>::quiet_NaN();
#else
		return -numeric_limits<double>::quiet_NaN();
#endif
	}
	if( !abs( binX ) || isInf( binY ) ) [[unlikely]] // x == 0 || y == Inf
		return x;
	auto exp = []( uint64_t b ) -> int { return b >> 52 & 0x7FF; };
	int
		expX = exp( binX ),
		expY = exp( binY );
	auto mant = []( uint64_t b ) { return b & MANT; };
	uint64_t
		mantX = mant( binX ),
		mantY = mant( binY );
	int headBits = 11;
	static auto normalize = [&]( int &exp, uint64_t &mant )
	{
		unsigned shift = countl_zero( mant ) - headBits;
		mant <<= shift;
		exp -= shift;
	};
	auto build = []( int &exp, uint64_t &mant )
	{
		if( exp ) [[likely]]
			mant |= IMPLICIT;
		else
		{
			exp = 1;
			normalize( exp, mant );
		}
	};
	build( expX, mantX );
	build( expY, mantY );
	int
		tailX = countr_zero( mantX ),
		tailY = countr_zero( mantY ),
		tailBits = tailX <= tailY ? tailX : tailY;
	mantX >>= tailBits;
	mantY >>= tailBits;
	headBits += tailBits;
	uint64_t signX = binX & SIGN;
	int expDiff;
#if defined(_MSC_VER) && !defined(__llvm__) && defined(_M_X64)
	while( (expDiff = expX - expY) > 0 )
	{
		unsigned bits = expDiff <= 63 ? expDiff : 63;
		unsigned long long hi = mantX >> 64 - bits, lo = mantX << bits, remainder;
		(void)_udiv128( hi, lo, mantY, &remainder );
		if( !remainder ) [[unlikely]]
			return bit_cast<double>( signX );
		mantX = remainder;
		expX -= bits;
		normalize( expX, mantX );
	}
#else
	while( (expDiff = expX - expY) > 0 )
	{
		unsigned bits = expDiff <= headBits ? expDiff : headBits;
		if( !(mantX = (mantX << bits) % mantY) ) [[unlikely]]
			return bit_cast<double>( signX );
		expX -= bits;
		normalize( expX, mantX );
	}
#endif
	if( !expDiff && mantX >= mantY ) [[unlikely]]
		if( (mantX -= mantY) ) [[likely]]
			normalize( expX, mantX );
		else
			return bit_cast<double>( signX );
	mantX <<= tailBits;
	mantY <<= tailBits;
	if( expX <= 0 ) [[unlikely]]
	{
		assert(expX >= -51);
		mantX = mantX >> (unsigned)(-expX + 1);
		expX = 0;
	}
	return bit_cast<double>( signX | (uint64_t)expX << 52 | mantX & MANT );
}

[toc] | [prev] | [next] | [standalone]


#121905

FromMichael S <already5chosen@yahoo.com>
Date2025-03-09 11:46 +0200
Message-ID<20250309114624.00000e85@yahoo.com>
In reply to#121904
On Sun, 9 Mar 2025 10:31:02 +0100
Bonita Montero <Bonita.Montero@gmail.com> wrote:

> This prints the same result (0.0) under Windows and Linux:
> 

I am no longer going to look at your code until you start posting full
files, with all includes and using directives.

[toc] | [prev] | [next] | [standalone]


#121906

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-09 10:54 +0100
Message-ID<vqjogs$lto0$1@raubtier-asyl.eternal-september.org>
In reply to#121905
Am 09.03.2025 um 10:46 schrieb Michael S:

>> This prints the same result (0.0) under Windows and Linux:

> I am no longer going to look at your code until you start posting full
> files, with all includes and using directives.

You could simply replace the single function I've shown.

[toc] | [prev] | [next] | [standalone]


#121907

FromMichael S <already5chosen@yahoo.com>
Date2025-03-09 12:09 +0200
Message-ID<20250309120931.0000036f@yahoo.com>
In reply to#121906
On Sun, 9 Mar 2025 10:54:40 +0100
Bonita Montero <Bonita.Montero@gmail.com> wrote:

> Am 09.03.2025 um 10:46 schrieb Michael S:
> 
> >> This prints the same result (0.0) under Windows and Linux:  
> 
> > I am no longer going to look at your code until you start posting
> > full files, with all includes and using directives.  
> 
> You could simply replace the single function I've shown.
> 

I can. I don't want to do it. 
You want me to look at/test your code? You post full code.
Simple, isn't it?



[toc] | [prev] | [next] | [standalone]


#121908

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-09 11:21 +0100
Message-ID<vqjq3v$m7h6$1@raubtier-asyl.eternal-september.org>
In reply to#121907
Am 09.03.2025 um 11:09 schrieb Michael S:
> On Sun, 9 Mar 2025 10:54:40 +0100
> Bonita Montero <Bonita.Montero@gmail.com> wrote:
> 
>> Am 09.03.2025 um 10:46 schrieb Michael S:
>>
>>>> This prints the same result (0.0) under Windows and Linux:
>>
>>> I am no longer going to look at your code until you start posting
>>> full files, with all includes and using directives.
>>
>> You could simply replace the single function I've shown.
>>
> 
> I can. I don't want to do it.
> You want me to look at/test your code? You post full code.
> Simple, isn't it?

I've read you don't trust my tests, so use your own with myFmod.

[toc] | [prev] | [next] | [standalone]


#121911

FromMichael S <already5chosen@yahoo.com>
Date2025-03-09 14:09 +0200
Message-ID<20250309140932.0000303d@yahoo.com>
In reply to#121908
On Sun, 9 Mar 2025 11:21:55 +0100
Bonita Montero <Bonita.Montero@gmail.com> wrote:

> Am 09.03.2025 um 11:09 schrieb Michael S:
> > On Sun, 9 Mar 2025 10:54:40 +0100
> > Bonita Montero <Bonita.Montero@gmail.com> wrote:
> >   
> >> Am 09.03.2025 um 10:46 schrieb Michael S:
> >>  
> >>>> This prints the same result (0.0) under Windows and Linux:  
> >>  
> >>> I am no longer going to look at your code until you start posting
> >>> full files, with all includes and using directives.  
> >>
> >> You could simply replace the single function I've shown.
> >>  
> > 
> > I can. I don't want to do it.
> > You want me to look at/test your code? You post full code.
> > Simple, isn't it?  
> 
> I've read you don't trust my tests, so use your own with myFmod.
> 

ok. I was too curios :(
This version produces correct results both when compiled under MSVC and
when compiled with other compilers. It is a little faster too. 
With MSVC on old Intel CPU it is only 2.5 times slower than standard
library in relevant range of x/y. Previous version was 3.4 times
slower. 
With gcc and clang it is still more than 6 times slower than standard
library.
The coding style is now less insane.

Measurements in nsec. 
First result - Intel Skylake at 4.25 GHz
Second result - AMD Zen3 at 3.7 GHz

abs(x/y) in range that matters [0.5:2**53]:
Standard MSVC Library -  11.1  10.4
Standard gnu Library  -   5.4  10.7
Yours (MSVc)          -  27.6  11.5
Yours (gcc)           -  36.4  23.7 
Yours (clang)         -  37.4  24.3

abs(x/y) in full range [2**-2090:2**2090]:
Standard MSVC Library - 109.4 153.5
Standard glib Library - 102.3 155.5
Yours (MSVc)          - 134.9  52.6
Yours (gcc)           - 284.7 151.8
Yours (clang)         - 285.2 156.5




[toc] | [prev] | [next] | [standalone]


#121915

FromMr Flibble <leigh@i42.co.uk>
Date2025-03-09 15:26 +0000
Message-ID<cocrsjdgqtmvrh221fbhje39aabopvb87h@4ax.com>
In reply to#121911
On Sun, 9 Mar 2025 14:09:32 +0200, Michael S
<already5chosen@yahoo.com> wrote:

>On Sun, 9 Mar 2025 11:21:55 +0100
>Bonita Montero <Bonita.Montero@gmail.com> wrote:
>
>> Am 09.03.2025 um 11:09 schrieb Michael S:
>> > On Sun, 9 Mar 2025 10:54:40 +0100
>> > Bonita Montero <Bonita.Montero@gmail.com> wrote:
>> >   
>> >> Am 09.03.2025 um 10:46 schrieb Michael S:
>> >>  
>> >>>> This prints the same result (0.0) under Windows and Linux:  
>> >>  
>> >>> I am no longer going to look at your code until you start posting
>> >>> full files, with all includes and using directives.  
>> >>
>> >> You could simply replace the single function I've shown.
>> >>  
>> > 
>> > I can. I don't want to do it.
>> > You want me to look at/test your code? You post full code.
>> > Simple, isn't it?  
>> 
>> I've read you don't trust my tests, so use your own with myFmod.
>> 
>
>ok. I was too curios :(
>This version produces correct results both when compiled under MSVC and
>when compiled with other compilers. It is a little faster too. 
>With MSVC on old Intel CPU it is only 2.5 times slower than standard
>library in relevant range of x/y. Previous version was 3.4 times
>slower. 
>With gcc and clang it is still more than 6 times slower than standard
>library.
>The coding style is now less insane.
>
>Measurements in nsec. 
>First result - Intel Skylake at 4.25 GHz
>Second result - AMD Zen3 at 3.7 GHz
>
>abs(x/y) in range that matters [0.5:2**53]:
>Standard MSVC Library -  11.1  10.4
>Standard gnu Library  -   5.4  10.7
>Yours (MSVc)          -  27.6  11.5
>Yours (gcc)           -  36.4  23.7 
>Yours (clang)         -  37.4  24.3
>
>abs(x/y) in full range [2**-2090:2**2090]:
>Standard MSVC Library - 109.4 153.5
>Standard glib Library - 102.3 155.5
>Yours (MSVc)          - 134.9  52.6
>Yours (gcc)           - 284.7 151.8
>Yours (clang)         - 285.2 156.5

So it is slow ergo a pointless alternative to what we already have.

/Flibble

[toc] | [prev] | [next] | [standalone]


#121916

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-09 17:02 +0100
Message-ID<vqke2j$qa42$1@raubtier-asyl.eternal-september.org>
In reply to#121915
Am 09.03.2025 um 16:26 schrieb Mr Flibble:

> So it is slow ergo a pointless alternative to what we already have.

glibc does it nearly in the same way I do it because the FMA-solution
isn't portable. If fma( a, b, c ) is substituted with a * b + c because
there's no proper CPU-instruction the whole issue doesn't work.
And with support for _udiv128 my solution has about the same performance
like the Michael's solution with clang++ 18.1.7.

[toc] | [prev] | [next] | [standalone]


#121918

FromMichael S <already5chosen@yahoo.com>
Date2025-03-09 19:55 +0200
Message-ID<20250309195521.00003ec4@yahoo.com>
In reply to#121916
On Sun, 9 Mar 2025 17:02:32 +0100
Bonita Montero <Bonita.Montero@gmail.com> wrote:

> Am 09.03.2025 um 16:26 schrieb Mr Flibble:
> 
> > So it is slow ergo a pointless alternative to what we already have.
> >  
> 
> glibc does it nearly in the same way I do it because the FMA-solution
> isn't portable.
> If fma( a, b, c ) is substituted with a * b + c
> because there's no proper CPU-instruction the whole issue doesn't
> work. 

FMA solution is portable to any standard-complaint C environment.
By standard, it has to work regardless of presence of absence of
FMA hardware.
In absence of FMA hardware it is expected to be rather slow, but still
has to produce correct results.

Unfortunately, Microsoft's library implementation of fma() does not work
correctly on non-FMA hardware. In case when x*y and z have different
signs it fairs somewhat better than when they have the same sign, but
still not good enough. 
So it goes ):
Since under msys2 both gcc and clang rely on Microsoft's library, they
also do not work correctly on non-FMA CPUs.

It would be interesting to test if glibc is better in that regard.
Unfortunately, right now I have no access to any glibc-based system
that runs on sufficiently old hardware.

Anyway, despite all their problems, fma() based solutions are written
in standard C language. The same can't be said about solutions that use
any variant of 128-bit integer arithmetic, either in form of Gnu
__int128 or in form of Microsoft's intrinsic functions.
I think that an absence of standardized 128-bit integer math in both C
and C++ sucks, but I can not change the fact.

> And with support for _udiv128 my solution has about the same
> performance like the Michael's solution with clang++ 18.1.7.
> 

I readily admitted that from practical perspective all 3 solutions
that I posted here (one of each is incorrect) are pointless.

I do have variants that are usefully faster than Standard library for
relevant x/y ratios, but I didn't post them here.
They achieve the speed boost via direct manipulation of binary64 bit
patterns. I am not sure that such solutions are on topic in c.l.c++.

Still, what you say about relative speed is true only on newer CPUs and
only when compiled with MSVC. On Older CPUs, like Intel Skylake, which
is pretty fast CPU on absolute scale and which still constitutes big
portion of installed base, your code is significantly slower than mine.
Same for newer CPUs with compilers that do not support native long
division.

Here is comparison vs code that I posted here at 2025-03-03 18:10:08
+0200:


Measurements in nsec. 
First result - Intel Skylake at 4.25 GHz
Second result - AMD Zen3 at 3.7 GHz

abs(x/y) in range that matters [0.5:2**53]:
Standard MSVC Library -  11.1  10.4
Standard gnu Library  -   5.4  10.7
Yours (MSVc)          -  27.6  11.5
Yours (gcc)           -  36.4  23.7 
Yours (clang)         -  37.4  24.3
my (MSVc)             -  10.7  11.3
my (gcc)              -   7.7   7.6 
my (clang)            -   6.3   7.5

abs(x/y) in full range [2**-2090:2**2090]:
Standard MSVC Library - 109.4 153.5
Standard glib Library - 102.3 155.5
Yours (MSVc)          - 134.9  52.6
Yours (gcc)           - 284.7 151.8
Yours (clang)         - 285.2 156.5
my (MSVc)             -  62.1  61.1
my (gcc)              -  60.8  59.1 
my (clang)            -  59.9  59.3




[toc] | [prev] | [next] | [standalone]


#121920

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-09 19:10 +0100
Message-ID<vqklia$rlr2$1@raubtier-asyl.eternal-september.org>
In reply to#121918
Am 09.03.2025 um 18:55 schrieb Michael S:

> In absence of FMA hardware it is expected to be rather slow, but still
> has to produce correct results.

Yes, extremely slow.

> It would be interesting to test if glibc is better in that regard.

glibc uses integer-operations.

> I readily admitted that from practical perspective all 3 solutions
> that I posted here (one of each is incorrect) are pointless.

I've recently posted a comparison of your solution against mine on
a Zen4-CPU with MSVC. Your solution is equally performant with close
exponents (0x3FF to 0x433) if I compile it unter WSL2 with g++-12.
The problem with MSVC is that the trunc() function is extremely slow.
In my implementation of your idea (x86 FMA) I use my own function
xtrunc which makes the code twice as fast.

> Still, what you say about relative speed is true only on newer CPUs and
> only when compiled with MSVC. ...

I haven't managed to write a 128 / 64 -> 64:64 division with Linux
-compilers. __int128 doesn't work since the compiler doesn't see that
the result fits in 64 bit and calls a library function for the division
which does the subtract and shift steps manually.
But your solution has about the same performance on Linux with g++12
like my code with MSVC on a Zen4-CPU.

[toc] | [prev] | [next] | [standalone]


#121922

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-09 19:27 +0100
Message-ID<vqkmi9$s6jt$1@raubtier-asyl.eternal-september.org>
In reply to#121920
Am 09.03.2025 um 19:10 schrieb Bonita Montero:

> I've recently posted a comparison of your solution against mine on
> a Zen4-CPU with MSVC. Your solution is equally performant with close
> exponents (0x3FF to 0x433) if I compile it unter WSL2 with g++-12.
> The problem with MSVC is that the trunc() function is extremely slow.
> In my implementation of your idea (x86 FMA) I use my own function
> xtrunc which makes the code twice as fast.

This is even somewhat faster since I'm using the ROUNDSD instruction
of SSE 4.1; but the difference to my xtrunc-solution is only 13%:

double fmody( double x, double y )
{
	if( isnan( x ) ) [[unlikely]]
		return x;
	if( isnan( y ) ) [[unlikely]]
		return y;
	if( isinf( x ) || !y ) [[unlikely]]
	{
		feraiseexcept( FE_INVALID );
		return numeric_limits<double>::quiet_NaN();
	}
	if( !x || isinf( y ) ) [[unlikely]]
		return x;
	uint64_t sign = bit_cast<uint64_t>( x ) & numeric_limits<int64_t>::min();
	x = abs( x );
	y = abs( y );
	int oldCsr = _mm_getcsr();
	constexpr int CHOP = 0x6000;
	_mm_setcsr( oldCsr | CHOP );
	constexpr uint64_t
		EXP = -(1ll << 52),
		MANT = ~EXP;
	uint64_t binY = bit_cast<uint64_t>( y );
	int64_t expY = binY & EXP;
	if( !expY ) [[unlikely]]
		expY = (uint64_t)(0 - (countl_zero( binY & MANT ) - 12)) << 52;
	while( x >= y )
	{
		auto floor = []( double value )
		{
			__m128d m;
#if defined(_MSC_VER)
			m.m128d_f64[0] = value;
			_mm_floor_sd(m, m);
			return m.m128d_f64[0];
#else
			m[0] = value;
			_mm_floor_sd(m, m);
			return m[0];
#endif
		};
		uint64_t yExpAdd = 0;
		double div = x / y;
		if( div < 0x1.FFFFFFFFFFFFFp+1023 ) [[likely]]
			div = xtrunc( div );
		else
		{
			uint64_t
				binX = bit_cast<uint64_t>( x ),
				newExp = expY + (54ull << 52);
			yExpAdd = (binX & EXP) - newExp;
			div = xtrunc( bit_cast<double>( newExp | binX & MANT ) / y );
		}
		auto xfma = []( double a, double b, double c )
		{
			__m128d mult1, mult2, add;
#if defined(_MSC_VER)
			mult1.m128d_f64[0] = a;
			mult2.m128d_f64[0] = b;
			add.m128d_f64[0] = c;
			return _mm_fmadd_sd( mult1, mult2, add ).m128d_f64[0];
#else
			mult1[0] = a;
			mult2[0] = b;
			add[0] = c;
			return _mm_fmadd_sd( mult1, mult2, add )[0];
#endif
		};
		x = xfma( div, -bit_cast<double>( binY + yExpAdd ), x );
		if( !x ) [[unlikely]]
			return bit_cast<double>( sign );
	}
	_mm_setcsr( oldCsr );
	return bit_cast<double>( sign | bit_cast<uint64_t>( x ) );
}

[toc] | [prev] | [next] | [standalone]


#121917

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-09 17:23 +0100
Message-ID<vqkf9p$qh6l$1@raubtier-asyl.eternal-september.org>
In reply to#121911
Am 09.03.2025 um 13:09 schrieb Michael S:

> Measurements in nsec.
> First result - Intel Skylake at 4.25 GHz
> Second result - AMD Zen3 at 3.7 GHz
> 
> abs(x/y) in range that matters [0.5:2**53]:
> Standard MSVC Library -  11.1  10.4
> Standard gnu Library  -   5.4  10.7
> Yours (MSVc)          -  27.6  11.5
> Yours (gcc)           -  36.4  23.7
> Yours (clang)         -  37.4  24.3
> 
> abs(x/y) in full range [2**-2090:2**2090]:
> Standard MSVC Library - 109.4 153.5
> Standard glib Library - 102.3 155.5
> Yours (MSVc)          - 134.9  52.6
> Yours (gcc)           - 284.7 151.8
> Yours (clang)         - 285.2 156.5

With MSVC and an arbitrary combination of finite x and y on my
Zen4-machine:

	your fmod: 77.1214
	my: 38.4486

With MSVC and an arbitrary combination of finite x with exponents
ranging from 0x3FF to 0x433 (close exponents) on my Zen4-machine:

	your fmod: 23.6423
	my: 9.79146

This is a nearly proper implementation of your idea with FMA-intrinsics
and SSE/AVX control register access:

double fmody( double x, double y )
{
	if( isnan( x ) ) [[unlikely]]
		return x;
	if( isnan( y ) ) [[unlikely]]
		return y;
	if( isinf( x ) || !y ) [[unlikely]]
	{
		feraiseexcept( FE_INVALID );
		return numeric_limits<double>::quiet_NaN();
	}
	if( !x || isinf( y ) ) [[unlikely]]
		return x;
	uint64_t sign = bit_cast<uint64_t>( x ) & numeric_limits<int64_t>::min();
	x = abs( x );
	y = abs( y );
	int oldCsr = _mm_getcsr();
	constexpr int CHOP = 0x6000;
	_mm_setcsr( oldCsr | CHOP );
	constexpr uint64_t
		EXP = -(1ll << 52),
		MANT = ~EXP;
	uint64_t binY = bit_cast<uint64_t>( y );
	int64_t expY = binY & EXP;
	if( !expY ) [[unlikely]]
		expY = (uint64_t)(0 - (countl_zero( binY & MANT ) - 12)) << 52;
	while( x >= y )
	{
		uint64_t yExpAdd = 0;
		double div = x / y;
		if( div < 0x1.FFFFFFFFFFFFFp+1023 ) [[likely]]
			div = xtrunc( div );
		else
		{
			uint64_t
				binX = bit_cast<uint64_t>( x ),
				newExp = expY + (54ull << 52);
			yExpAdd = (binX & EXP) - newExp;
			div = xtrunc( bit_cast<double>( newExp | binX & MANT ) / y );
		}
		__m128d mult1, mult2, add;
#if defined(_MSC_VER)
		mult1.m128d_f64[0] = div;
		mult2.m128d_f64[0] = -bit_cast<double>( binY + yExpAdd );
		add.m128d_f64[0] = x;
		x = _mm_fmadd_sd( mult1, mult2, add ).m128d_f64[0];
#else
		mult1[0] = div;
		mult2[0] = -bit_cast<double>( binY + yExpAdd );
		add[0] = x;
		x = _mm_fmadd_sd( mult1, mult2, add )[0];
#endif
		if( !x ) [[unlikely]]
			return bit_cast<double>( sign );
	}
	_mm_setcsr( oldCsr );
	return bit_cast<double>( sign | bit_cast<uint64_t>( x ) );
}

The only thing that doesn't work currently is the support for denormal
values.

[toc] | [prev] | [next] | [standalone]


#121919

FromMichael S <already5chosen@yahoo.com>
Date2025-03-09 20:04 +0200
Message-ID<20250309200407.0000036c@yahoo.com>
In reply to#121917
On Sun, 9 Mar 2025 17:23:26 +0100
Bonita Montero <Bonita.Montero@gmail.com> wrote:

> Am 09.03.2025 um 13:09 schrieb Michael S:
> 
> > Measurements in nsec.
> > First result - Intel Skylake at 4.25 GHz
> > Second result - AMD Zen3 at 3.7 GHz
> > 
> > abs(x/y) in range that matters [0.5:2**53]:
> > Standard MSVC Library -  11.1  10.4
> > Standard gnu Library  -   5.4  10.7
> > Yours (MSVc)          -  27.6  11.5
> > Yours (gcc)           -  36.4  23.7
> > Yours (clang)         -  37.4  24.3
> > 
> > abs(x/y) in full range [2**-2090:2**2090]:
> > Standard MSVC Library - 109.4 153.5
> > Standard glib Library - 102.3 155.5
> > Yours (MSVc)          - 134.9  52.6
> > Yours (gcc)           - 284.7 151.8
> > Yours (clang)         - 285.2 156.5  
> 
> With MSVC and an arbitrary combination of finite x and y on my
> Zen4-machine:
> 
> 	your fmod: 77.1214
> 	my: 38.4486
> 
> With MSVC and an arbitrary combination of finite x with exponents
> ranging from 0x3FF to 0x433 (close exponents) on my Zen4-machine:
> 
> 	your fmod: 23.6423
> 	my: 9.79146
> 


It looks like you didn't pay attention to a "flipflop" version that I
posted at 2025-03-03 18:10:08

> This is a nearly proper implementation of your idea with
> FMA-intrinsics and SSE/AVX control register access:
> 
> double fmody( double x, double y )
> {
> 	if( isnan( x ) ) [[unlikely]]
> 		return x;
> 	if( isnan( y ) ) [[unlikely]]
> 		return y;
> 	if( isinf( x ) || !y ) [[unlikely]]
> 	{
> 		feraiseexcept( FE_INVALID );
> 		return numeric_limits<double>::quiet_NaN();
> 	}
> 	if( !x || isinf( y ) ) [[unlikely]]
> 		return x;
> 	uint64_t sign = bit_cast<uint64_t>( x ) &
> numeric_limits<int64_t>::min(); x = abs( x );
> 	y = abs( y );
> 	int oldCsr = _mm_getcsr();
> 	constexpr int CHOP = 0x6000;
> 	_mm_setcsr( oldCsr | CHOP );
> 	constexpr uint64_t
> 		EXP = -(1ll << 52),
> 		MANT = ~EXP;
> 	uint64_t binY = bit_cast<uint64_t>( y );
> 	int64_t expY = binY & EXP;
> 	if( !expY ) [[unlikely]]
> 		expY = (uint64_t)(0 - (countl_zero( binY & MANT ) -
> 12)) << 52; while( x >= y )
> 	{
> 		uint64_t yExpAdd = 0;
> 		double div = x / y;
> 		if( div < 0x1.FFFFFFFFFFFFFp+1023 ) [[likely]]
> 			div = xtrunc( div );
> 		else
> 		{
> 			uint64_t
> 				binX = bit_cast<uint64_t>( x ),
> 				newExp = expY + (54ull << 52);
> 			yExpAdd = (binX & EXP) - newExp;
> 			div = xtrunc( bit_cast<double>( newExp | binX
> & MANT ) / y ); }
> 		__m128d mult1, mult2, add;
> #if defined(_MSC_VER)
> 		mult1.m128d_f64[0] = div;
> 		mult2.m128d_f64[0] = -bit_cast<double>( binY +
> yExpAdd ); add.m128d_f64[0] = x;
> 		x = _mm_fmadd_sd( mult1, mult2, add ).m128d_f64[0];
> #else
> 		mult1[0] = div;
> 		mult2[0] = -bit_cast<double>( binY + yExpAdd );
> 		add[0] = x;
> 		x = _mm_fmadd_sd( mult1, mult2, add )[0];
> #endif
> 		if( !x ) [[unlikely]]
> 			return bit_cast<double>( sign );
> 	}
> 	_mm_setcsr( oldCsr );
> 	return bit_cast<double>( sign | bit_cast<uint64_t>( x ) );
> }
> 
> The only thing that doesn't work currently is the support for denormal
> values.
> 

I already said that I don't approve non-portable constructs like
_mm_getcsr()/_mm_setcsr() except when they help important cases and
help ALOT. Neither applies here.

[toc] | [prev] | [next] | [standalone]


#121921

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-09 19:11 +0100
Message-ID<vqklks$rlr2$2@raubtier-asyl.eternal-september.org>
In reply to#121919
Am 09.03.2025 um 19:04 schrieb Michael S:

> I already said that I don't approve non-portable constructs like
> _mm_getcsr()/_mm_setcsr() except when they help important cases and
> help ALOT. Neither applies here.

The solution is much simpler than your solution since there are no
separate fast ans slow paths. The performance is about the same for
close exponents like your solution.

[toc] | [prev] | [next] | [standalone]


#121923

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-09 20:11 +0100
Message-ID<vqkp54$so65$1@raubtier-asyl.eternal-september.org>
In reply to#121921
Am 09.03.2025 um 19:11 schrieb Bonita Montero:

> The solution is much simpler than your solution since there are no
> separate fast ans slow paths. The performance is about the same for
> close exponents like your solution.

And it's somewhat faster if I use the ROUNDSD-intrinsic than my
solution before with the xtrunc-function. With MSVC's own trunc()
code the performance is not competitive.

[toc] | [prev] | [next] | [standalone]


#121924

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-10 07:24 +0100
Message-ID<vqm0id$17aku$1@raubtier-asyl.eternal-september.org>
In reply to#121919
Am 09.03.2025 um 19:04 schrieb Michael S:

> I already said that I don't approve non-portable constructs like
> _mm_getcsr()/_mm_setcsr() except when they help important cases and
> help ALOT. Neither applies here.

I dropped getting and setting the MSCSR-register to set the roun-
ding mode. Now I set the rounding mode directly with the intrinsics
_mm_div_round_sd and and _mm_fmadd_round_sd. Now this more manual
code does help "ALOT", i.e. the solution is 2/3 faster than your
initial solution with clang++-18 under Linux.
But there's still a problem with the denormals.

double fmodMplus( double x, double y )
{
	if( isnan( x ) ) [[unlikely]]
		return x;
	if( isnan( y ) ) [[unlikely]]
		return y;
	if( isinf( x ) || !y ) [[unlikely]]
	{
		feraiseexcept( FE_INVALID );
		return numeric_limits<double>::quiet_NaN();
	}
	if( !x || isinf( y ) ) [[unlikely]]
		return x;
	uint64_t sign = bit_cast<uint64_t>( x ) & numeric_limits<int64_t>::min();
	x = abs( x );
	y = abs( y );
	constexpr uint64_t
		EXP = -(1ll << 52),
		MANT = ~EXP;
	uint64_t binY = bit_cast<uint64_t>( y );
	int64_t expY = binY & EXP;
	//if( !expY ) [[unlikely]]
		//expY = (uint64_t)(0 - (countl_zero( binY & MANT ) - 12)) << 52;
	while( x >= y )
	{
		uint64_t yExpAdd = 0;
		__m128d a128, b128;
#if defined(_MSC_VER)
		a128.m128d_f64[0] = x;
		b128.m128d_f64[0] = y;
		double div = _mm_div_round_sd( a128, b128, _MM_FROUND_TO_ZERO | 
_MM_FROUND_NO_EXC ).m128d_f64[0];
#else
		a128[0] = x;
		b128[0] = y;
		double div = _mm_div_round_sd( a128, b128, _MM_FROUND_TO_ZERO | 
_MM_FROUND_NO_EXC )[0];
#endif
		if( div < 0x1.FFFFFFFFFFFFFp+1023 ) [[likely]]
			div = xtrunc( div );
		else
		{
			uint64_t
				binX = bit_cast<uint64_t>( x ),
				newExp = expY + (54ull << 52);
			yExpAdd = (binX & EXP) - newExp;
			div = xtrunc( bit_cast<double>( newExp | binX & MANT ) / y );
		}
		x = []( double a, double b, double c )
		{
			__m128d mult1, mult2, add;
#if defined(_MSC_VER)
			mult1.m128d_f64[0] = a;
			mult2.m128d_f64[0] = b;
			add.m128d_f64[0] = c;
			return _mm_fmadd_round_sd( mult1, mult2, add, _MM_FROUND_TO_ZERO | 
_MM_FROUND_NO_EXC ).m128d_f64[0];
#else
			mult1[0] = a;
			mult2[0] = b;
			add[0] = c;
			return _mm_fmadd_round_sd( mult1, mult2, add, _MM_FROUND_TO_ZERO | 
_MM_FROUND_NO_EXC )[0];
#endif
		}( div, -bit_cast<double>( binY + yExpAdd ), x );
		if( !x ) [[unlikely]]
			return bit_cast<double>( sign );
	}
	return bit_cast<double>( sign | bit_cast<uint64_t>( x ) );
}

[toc] | [prev] | [next] | [standalone]


#121925

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-10 10:46 +0100
Message-ID<vqmcee$19g55$1@raubtier-asyl.eternal-september.org>
In reply to#121924
I tried to use a unsigned __int128 / uint64_t division and I expected
that the compiler calls a library function which does the subtract and
shift manually. But g++ as well as clang++ handle this as a 128 : 64
-> 64#64 division somehow.
And now my original solution is about 23% faster than your solution
for close exponents (exponent difference <= 53) and for arbitrary
exponent differences your solution is about 3% faster.

double fmodO( double x, double y )
{
	constexpr uint64_t
		SIGN = 1ull << 63,
		IMPLICIT = 1ull << 52,
		MANT = IMPLICIT - 1,
		QBIT = 1ull << 51;
	uint64_t const
		binX = bit_cast<uint64_t>( x ),
		binY = bit_cast<uint64_t>( y );
	static auto abs = []( uint64_t m ) { return m & ~SIGN; };
	auto isNaN = []( uint64_t m ) { return abs( m ) >= 0x7FF0000000000001u; };
	auto isSig = []( uint64_t m ) { return !(m & QBIT); };
	if( isNaN( binX ) ) [[unlikely]] // x == NaN
#if defined(_MSC_VER)
		return bit_cast<double>( isNaN( binY ) ? binY | binX & binY & QBIT : 
binX );
#else
	{
		if( isSig( binX ) || isNaN( binY ) && isSig( binY ) ) [[unlikely]]
			feraiseexcept( FE_INVALID );
		return bit_cast<double>( binX | QBIT );
	}
#endif
	if( isNaN( binY ) ) [[unlikely]] // x != NaN || y == NaN
#if defined(_MSC_VER)
		return y;
#else
	{
		if( isSig( binY ) ) [[unlikely]]
			feraiseexcept( FE_INVALID );
		return bit_cast<double>( binY | QBIT );
	}
#endif
	auto isInf = []( uint64_t m ) { return abs( m ) == 0x7FF0000000000000u; };
	if( isInf( binX ) ) // x == Inf
	{
		feraiseexcept( FE_INVALID );
#if defined(_MSC_VER)
		return bit_cast<double>( binX & ~MANT | QBIT );
#else
		return -numeric_limits<double>::quiet_NaN();
#endif
	}
	if( !abs( binY ) ) [[unlikely]] // y == 0
	{
		feraiseexcept( FE_INVALID );
#if defined(_MSC_VER)
		return numeric_limits<double>::quiet_NaN();
#else
		return -numeric_limits<double>::quiet_NaN();
#endif
	}
	if( !abs( binX ) || isInf( binY ) ) [[unlikely]] // x == 0 || y == Inf
		return x;
	auto exp = []( uint64_t b ) -> int { return b >> 52 & 0x7FF; };
	int
		expX = exp( binX ),
		expY = exp( binY );
	auto mant = []( uint64_t b ) { return b & MANT; };
	uint64_t
		mantX = mant( binX ),
		mantY = mant( binY );
	int headBits = 11;
	static auto normalize = [&]( int &exp, uint64_t &mant )
	{
		unsigned shift = countl_zero( mant ) - headBits;
		mant <<= shift;
		exp -= shift;
	};
	auto build = []( int &exp, uint64_t &mant )
	{
		if( exp ) [[likely]]
			mant |= IMPLICIT;
		else
		{
			exp = 1;
			normalize( exp, mant );
		}
	};
	build( expX, mantX );
	build( expY, mantY );
	int
		tailX = countr_zero( mantX ),
		tailY = countr_zero( mantY ),
		tailBits = tailX <= tailY ? tailX : tailY;
	mantX >>= tailBits;
	mantY >>= tailBits;
	headBits += tailBits;
	uint64_t signX = binX & SIGN;
	int expDiff;
#if defined(_MSC_VER) && !defined(__llvm__) && defined(_M_X64)
	while( (expDiff = expX - expY) > 0 )
	{
		unsigned bits = expDiff <= 63 ? expDiff : 63;
		unsigned long long hi = mantX >> 64 - bits, lo = mantX << bits, remainder;
		(void)_udiv128( hi, lo, mantY, &remainder );
		if( !remainder ) [[unlikely]]
			return bit_cast<double>( signX );
		mantX = remainder;
		expX -= bits;
		normalize( expX, mantX );
	}
#elif defined(__GNUC__) || defined(__clang__)
	while( (expDiff = expX - expY) > 0 )
	{
		unsigned bits = expDiff <= 63 ? expDiff : 63;
		unsigned __int128 dividend = (unsigned __int128)mantX << bits;
		mantX = (uint64_t)(dividend % mantY);
		if( !mantX ) [[unlikely]]
			return bit_cast<double>( signX );
		expX -= bits;
		normalize( expX, mantX );
	}
#else
	while( (expDiff = expX - expY) > 0 )
	{
		unsigned bits = expDiff <= headBits ? expDiff : headBits;
		if( !(mantX = (mantX << bits) % mantY) ) [[unlikely]]
			return bit_cast<double>( signX );
		expX -= bits;
		normalize( expX, mantX );
	}
#endif
	if( !expDiff && mantX >= mantY ) [[unlikely]]
		if( (mantX -= mantY) ) [[likely]]
			normalize( expX, mantX );
		else
			return bit_cast<double>( signX );
	mantX <<= tailBits;
	mantY <<= tailBits;
	if( expX <= 0 ) [[unlikely]]
	{
		assert(expX >= -51);
		mantX = mantX >> (unsigned)(-expX + 1);
		expX = 0;
	}
	return bit_cast<double>( signX | (uint64_t)expX << 52 | mantX & MANT );
}

[toc] | [prev] | [next] | [standalone]


#121930

FromMichael S <already5chosen@yahoo.com>
Date2025-03-10 14:26 +0200
Message-ID<20250310142648.00005b3c@yahoo.com>
In reply to#121925
On Mon, 10 Mar 2025 10:46:59 +0100
Bonita Montero <Bonita.Montero@gmail.com> wrote:

> I tried to use a unsigned __int128 / uint64_t division and I expected
> that the compiler calls a library function which does the subtract and
> shift manually. But g++ as well as clang++ handle this as a 128 : 64
> -> 64#64 division somehow.  


Somehow?
It should be an obvious thing to anybody who cared to think for 15
seconds.
A library-or-compiler starts with hi1=rem(0:x_hi, y). Now hi1 is
guaranteed to be smaller than y, so it's safe to do rem(hi1:x_lo, y).
It is not *very* slow, but still there are 2 dependent division
operations. 
So, on machines with slow integer division, like Skylake, it is 1.5-1.7
times slower than a single long division.
On machines with fast long division, like Zen3/4/5 or "performance"
cores on newer Intel CPUs, it is approximately twice slower than a
single long division. Plus call overhead, so 2.5x or so slower overall.

> And now my original solution is about 23% faster than your solution
> for close exponents (exponent difference <= 53) and for arbitrary
> exponent differences your solution is about 3% faster.
> 

That's absolutely not what I see. 
Here are my measurements:

Measurements in nsec. 
First result - Intel Skylake at 4.25 GHz
Second result - AMD Zen3 at 3.7 GHz

abs(x/y) in range that matters [0.5:2**53]:
Standard MSVC Library -  11.1  10.4
Standard gnu Library  -   5.4  10.7
Yours (MSVc)          -  27.6  11.5
Yours (gcc)           -  36.4  23.7 
Yours (clang)         -  37.4  24.3
my (MSVc)             -  10.7  11.3
my (gcc)              -   7.7   7.6 
my (clang)            -   6.3   7.5
Your last (MSVc)      -  27.6  11.6
Your last (gcc)       -  33.8  28.6
Your last (clang)     -  32.6  26.9

abs(x/y) in full range [2**-2090:2**2090]:
Standard MSVC Library - 109.4 153.5
Standard glib Library - 102.3 155.5
Yours (MSVc)          - 134.9  52.6
Yours (gcc)           - 284.7 151.8
Yours (clang)         - 285.2 156.5
my (MSVc)             -  62.1  61.1
my (gcc)              -  60.8  59.1 
my (clang)            -  59.9  59.3
Your last (MSVc)      - 135.0  52.5
Your last (gcc)       - 172.1 137.3
Your last (clang)     - 167.7 126.3


It looks like you are not using version that I posted at 2025-03-03
as a reference.
The only case where you code is running at approximately the same speed
as my code is MSVC-generated code on CPUs with fast integer division.
And it was like that since your previous version. I see no changes in
that regard.

> double fmodO( double x, double y )
> {
> 	constexpr uint64_t
> 		SIGN = 1ull << 63,
> 		IMPLICIT = 1ull << 52,
> 		MANT = IMPLICIT - 1,
> 		QBIT = 1ull << 51;
> 	uint64_t const
> 		binX = bit_cast<uint64_t>( x ),
> 		binY = bit_cast<uint64_t>( y );
> 	static auto abs = []( uint64_t m ) { return m & ~SIGN; };
> 	auto isNaN = []( uint64_t m ) { return abs( m ) >=
> 0x7FF0000000000001u; }; auto isSig = []( uint64_t m ) { return !(m &
> QBIT); }; if( isNaN( binX ) ) [[unlikely]] // x == NaN
> #if defined(_MSC_VER)
> 		return bit_cast<double>( isNaN( binY ) ? binY | binX
> & binY & QBIT : binX );
> #else
> 	{
> 		if( isSig( binX ) || isNaN( binY ) && isSig( binY ) )
> [[unlikely]] feraiseexcept( FE_INVALID );
> 		return bit_cast<double>( binX | QBIT );
> 	}
> #endif
> 	if( isNaN( binY ) ) [[unlikely]] // x != NaN || y == NaN
> #if defined(_MSC_VER)
> 		return y;
> #else
> 	{
> 		if( isSig( binY ) ) [[unlikely]]
> 			feraiseexcept( FE_INVALID );
> 		return bit_cast<double>( binY | QBIT );
> 	}
> #endif
> 	auto isInf = []( uint64_t m ) { return abs( m ) ==
> 0x7FF0000000000000u; }; if( isInf( binX ) ) // x == Inf
> 	{
> 		feraiseexcept( FE_INVALID );
> #if defined(_MSC_VER)
> 		return bit_cast<double>( binX & ~MANT | QBIT );
> #else
> 		return -numeric_limits<double>::quiet_NaN();
> #endif
> 	}
> 	if( !abs( binY ) ) [[unlikely]] // y == 0
> 	{
> 		feraiseexcept( FE_INVALID );
> #if defined(_MSC_VER)
> 		return numeric_limits<double>::quiet_NaN();
> #else
> 		return -numeric_limits<double>::quiet_NaN();
> #endif
> 	}
> 	if( !abs( binX ) || isInf( binY ) ) [[unlikely]] // x == 0 ||
> y == Inf return x;
> 	auto exp = []( uint64_t b ) -> int { return b >> 52 & 0x7FF;
> }; int
> 		expX = exp( binX ),
> 		expY = exp( binY );
> 	auto mant = []( uint64_t b ) { return b & MANT; };
> 	uint64_t
> 		mantX = mant( binX ),
> 		mantY = mant( binY );
> 	int headBits = 11;
> 	static auto normalize = [&]( int &exp, uint64_t &mant )
> 	{
> 		unsigned shift = countl_zero( mant ) - headBits;
> 		mant <<= shift;
> 		exp -= shift;
> 	};
> 	auto build = []( int &exp, uint64_t &mant )
> 	{
> 		if( exp ) [[likely]]
> 			mant |= IMPLICIT;
> 		else
> 		{
> 			exp = 1;
> 			normalize( exp, mant );
> 		}
> 	};
> 	build( expX, mantX );
> 	build( expY, mantY );
> 	int
> 		tailX = countr_zero( mantX ),
> 		tailY = countr_zero( mantY ),
> 		tailBits = tailX <= tailY ? tailX : tailY;
> 	mantX >>= tailBits;
> 	mantY >>= tailBits;
> 	headBits += tailBits;
> 	uint64_t signX = binX & SIGN;
> 	int expDiff;
> #if defined(_MSC_VER) && !defined(__llvm__) && defined(_M_X64)
> 	while( (expDiff = expX - expY) > 0 )
> 	{
> 		unsigned bits = expDiff <= 63 ? expDiff : 63;
> 		unsigned long long hi = mantX >> 64 - bits, lo =
> mantX << bits, remainder; (void)_udiv128( hi, lo, mantY, &remainder );
> 		if( !remainder ) [[unlikely]]
> 			return bit_cast<double>( signX );
> 		mantX = remainder;
> 		expX -= bits;
> 		normalize( expX, mantX );
> 	}
> #elif defined(__GNUC__) || defined(__clang__)
> 	while( (expDiff = expX - expY) > 0 )
> 	{
> 		unsigned bits = expDiff <= 63 ? expDiff : 63;
> 		unsigned __int128 dividend = (unsigned __int128)mantX
> << bits; mantX = (uint64_t)(dividend % mantY);
> 		if( !mantX ) [[unlikely]]
> 			return bit_cast<double>( signX );
> 		expX -= bits;
> 		normalize( expX, mantX );
> 	}
> #else
> 	while( (expDiff = expX - expY) > 0 )
> 	{
> 		unsigned bits = expDiff <= headBits ? expDiff :
> headBits; if( !(mantX = (mantX << bits) % mantY) ) [[unlikely]]
> 			return bit_cast<double>( signX );
> 		expX -= bits;
> 		normalize( expX, mantX );
> 	}
> #endif
> 	if( !expDiff && mantX >= mantY ) [[unlikely]]
> 		if( (mantX -= mantY) ) [[likely]]
> 			normalize( expX, mantX );
> 		else
> 			return bit_cast<double>( signX );
> 	mantX <<= tailBits;
> 	mantY <<= tailBits;
> 	if( expX <= 0 ) [[unlikely]]
> 	{
> 		assert(expX >= -51);
> 		mantX = mantX >> (unsigned)(-expX + 1);
> 		expX = 0;
> 	}
> 	return bit_cast<double>( signX | (uint64_t)expX << 52 | mantX
> & MANT ); }


You code would be much, much cleaner and more readable if you replace
lambdas with proper functions. Or just write simple expressions like 'x
& MANT' in place.



[toc] | [prev] | [next] | [standalone]


#121931

FromBonita Montero <Bonita.Montero@gmail.com>
Date2025-03-10 13:45 +0100
Message-ID<vqmmt1$1bjh1$1@raubtier-asyl.eternal-september.org>
In reply to#121930
Am 10.03.2025 um 13:26 schrieb Michael S:

> It should be an obvious thing to anybody who cared to think for 15
> seconds.

I was wrong and it absolutels isn't obvious. The compiler calls the
glibc function __umodti3 of glibc which has a shortcut for results
which fit into 64 bit. Although there's an additional call on Linux
the code with clang++-18 is still a bit faster than my Windows solution
with the _udiv128-intrinsic; that's really surprisng.

> A library-or-compiler starts with hi1=rem(0:x_hi, y). Now hi1 is
> guaranteed to be smaller than y, so it's safe to do rem(hi1:x_lo, y).
> It is not *very* slow, but still there are 2 dependent division
> operations.

Both parameters are variable so there could be no static evaluation
at compile tiime.

> Measurements in nsec.
> First result - Intel Skylake at 4.25 GHz
> Second result - AMD Zen3 at 3.7 GHz
> 
> abs(x/y) in range that matters [0.5:2**53]:
> Standard MSVC Library -  11.1  10.4
> Standard gnu Library  -   5.4  10.7
> Yours (MSVc)          -  27.6  11.5
> Yours (gcc)           -  36.4  23.7
> Yours (clang)         -  37.4  24.3
> my (MSVc)             -  10.7  11.3
> my (gcc)              -   7.7   7.6
> my (clang)            -   6.3   7.5
> Your last (MSVc)      -  27.6  11.6
> Your last (gcc)       -  33.8  28.6
> Your last (clang)     -  32.6  26.9
> 
> abs(x/y) in full range [2**-2090:2**2090]:
> Standard MSVC Library - 109.4 153.5
> Standard glib Library - 102.3 155.5
> Yours (MSVc)          - 134.9  52.6
> Yours (gcc)           - 284.7 151.8
> Yours (clang)         - 285.2 156.5
> my (MSVc)             -  62.1  61.1
> my (gcc)              -  60.8  59.1
> my (clang)            -  59.9  59.3
> Your last (MSVc)      - 135.0  52.5
> Your last (gcc)       - 172.1 137.3
> Your last (clang)     - 167.7 126.3

This are the clang++-18 results on my Zen4-computer under WSL2 with
close exponents (0x3ff to 0x433):

	fmodO: 9.42929
	fmodM: 11.7907

So my code is about 23% faster on my computer.

This are the results for arbitrary exponents:

	fmodO: 41.9115
	fmodM: 41.2062

Exactly what I already mentioned.

Maybe that depends on the glibc-version because a different glibc
version might have different efficient __umodti3 functions.

> You code would be much, much cleaner and more readable if you replace
> lambdas with proper functions. ..

For me that doesn't make a difference.

[toc] | [prev] | [next] | [standalone]


Page 5 of 7 — ← Prev page 1 2 3 4 [5] 6 7  Next page →

Back to top | Article view | comp.lang.c++


csiph-web