- How to get mantissa of long double? - 11 Updates
- rational numbers - 1 Update
- Tricky ... - 9 Updates
- Most efficient prefetching distance - 3 Updates
| Bonita Montero <Bonita.Montero@gmail.com>: Oct 02 12:09PM +0200 Am 01.10.2021 um 17:37 schrieb wij: > x=::ldexpl(x,numeric_limits<FType>::digits); > mint= static_cast<int64_t>(x); > Result (mint) is a negative number, something not right!!! Here, exactly 100 lines with a very convenient double to double parts and double parts to double conversion: #pragma once #include <limits> #include <cstdint> #include <cassert> struct dbl_parts { static_assert(std::numeric_limits<double>::is_iec559, "must be standard fp"); dbl_parts( double d ); dbl_parts &operator =( double d ); dbl_parts() = default; operator double(); bool getSign(); std::uint16_t getBiasedExponent(); std::int16_t getExponent(); std::uint64_t getMantissa(); void setSign( bool sign ); void setBiasedExponent( uint16_t exp ); void setExponent( int16_t exp ); void setMantissa( uint64_t mantissa ); private: union { double value; std::uint64_t binary; }; }; inline dbl_parts::dbl_parts( double d ) : value( d ) { } inline dbl_parts &dbl_parts::operator =( double d ) { value = d; return *this; } inline dbl_parts::operator double() { return value; } inline bool dbl_parts::getSign() { return (int64_t)binary < 0; } inline std::uint16_t dbl_parts::getBiasedExponent() { return (std::uint16_t)(binary >> 52) & 0x7FF; } inline int16_t dbl_parts::getExponent() { return (int16_t)getBiasedExponent() - 0x3FF; } inline std::uint64_t dbl_parts::getMantissa() { std::uint16_t bExp = getBiasedExponent(); std::uint64_t hiBit = (uint64_t)(bExp && bExp != 0x7FF) << 52; return binary & 0xFFFFFFFFFFFFFu | hiBit; } inline void dbl_parts::setSign( bool sign ) { binary = binary & 0x7FFFFFFFFFFFFFFFu | (std::uint64_t)sign << 63; } inline void dbl_parts::setBiasedExponent( std::uint16_t exp ) { assert(exp <= 0x7FF); binary = binary & 0x800FFFFFFFFFFFFFu | (std::uint64_t)exp << 52; } inline void dbl_parts::setExponent( std::int16_t exp ) { assert(exp >= -0x3FF && exp <= 400); setBiasedExponent( (uint16_t)(exp - 0x3FF) ); } inline void dbl_parts::setMantissa( std::uint64_t mantissa ) { assert((getBiasedExponent() == 0 || getBiasedExponent() == 0x7FF) && !(mantissa & -0x10000000000000)); assert(getBiasedExponent() != 0 && getBiasedExponent() != 0x7FF || mantissa <= 0x1FFFFFFFFFFFFFu); binary = binary & 0xFFF0000000000000u | mantissa & 0xFFFFFFFFFFFFFu; } |
| Branimir Maksimovic <branimir.maksimovic@icloud.com>: Oct 02 10:59AM > the conversion to long long have defined behavior, the result of that > conversion would be the truncated value itself (7.3.10p1), NOT the > mantissa of the truncated value. What makes you think otherwise? Because mantissa is whole part of floating point number? -- 7-77-777 Evil Sinner! |
| Manfred <noname@add.invalid>: Oct 02 06:58PM +0200 On 10/2/2021 2:23 AM, wij wrote: >>>> mint= static_cast<int64_t>(x); >>>> Result (mint) is a negative number, something not right!!! >> I can't duplicate this problem: I get mint:9223372036854775807. <snip> > 16777215, ffffff > 9007199254740991, 1fffffffffffff > -9223372036854775808, 8000000000000000 There are two problems: 1) The templated function uses 'frexp' and 'ldexp', which take both double arguments (not *long* double), hence UB occurs at those calls for the 'long double' type whenever this type is actually larger than 'double'. 2) On my Linux box numeric_limits<*long* double>::digits is 64 (numeric_limits<double>::digits is 53), so the static_cast<int64_t>(x) yields UB again. ========= #include <cmath> #include <limits> #include <iostream> using namespace std; #define ENDL endl uint64_t get_mantf(float x) { int iexp; x=frexp(x,&iexp); x=ldexp(x,numeric_limits<float>::digits); return static_cast<uint64_t>(x); }; uint64_t get_mant(double x) { int iexp; x=frexp(x,&iexp); x=ldexp(x,numeric_limits<double>::digits); return static_cast<uint64_t>(x); }; uint64_t get_mantl(long double x) { int iexp; x=frexp(x,&iexp); x=ldexp(x,numeric_limits<long double>::digits); return static_cast<uint64_t>(x); }; int main() { cout << dec << numeric_limits<float>::digits << ", " << get_mantf(numeric_limits<float>::max()) << ", " << hex << get_mantf(numeric_limits<float>::max()) << ENDL; cout << dec << numeric_limits<double>::digits << ", " << get_mant(numeric_limits<double>::max()) << ", " << hex << get_mant(numeric_limits<double>::max()) << ENDL; cout << dec << numeric_limits<long double>::digits << ", " << get_mantl(numeric_limits<long double>::max()) << ", " << hex << get_mantl(numeric_limits<long double>::max()) << ENDL; return 0; } =================== $ c++ -std=c++11 -O2 -Wall mant.cc && ./a.out 24, 16777215, ffffff 53, 9007199254740991, 1fffffffffffff 64, 18446744073709551615, ffffffffffffffff |
| Manfred <noname@add.invalid>: Oct 02 07:21PM +0200 On 10/2/2021 6:58 PM, Manfred wrote: > 24, 16777215, ffffff > 53, 9007199254740991, 1fffffffffffff > 64, 18446744073709551615, ffffffffffffffff Sorry, that should have been: ===== uint64_t get_mantf(float x) { int iexp; x=frexpf(x,&iexp); x=ldexpf(x,numeric_limits<float>::digits); return static_cast<uint64_t>(x); }; uint64_t get_mant(double x) { int iexp; x=frexp(x,&iexp); x=ldexp(x,numeric_limits<double>::digits); return static_cast<uint64_t>(x); }; uint64_t get_mantl(long double x) { int iexp; x=frexpl(x,&iexp); x=ldexpl(x,numeric_limits<long double>::digits); return static_cast<uint64_t>(x); }; ===== However, the three distinct functions with frexp and ldexp in all three still work on my box (I'm guessing gcc is still able to compile the correct implementation in in this case), but the template doesn't. |
| James Kuyper <jameskuyper@alumni.caltech.edu>: Oct 02 02:57PM -0400 On 10/2/21 6:59 AM, Branimir Maksimovic wrote: >> conversion would be the truncated value itself (7.3.10p1), NOT the >> mantissa of the truncated value. What makes you think otherwise? > Because mantissa is whole part of floating point number? Well, at least I'm clear now about what your confusion is. I'll give you an answer in two parts: 1. The mantissa of a floating point number (also called the significand, which is the term used in the C standard in text that is incorporated by reference into the C++ standard) is something quite different from the whole part of that number. See <https://en.m.wikipedia.org/wiki/Significand> for details. 2. When a floating point number is greater than LLONG_MAX+1.0, the code you provided has undefined behavior. That makes sense, since a long long object cannot represent the whole part of such a number. The actual behavior can vary from one implementation to another, but on my system, it does NOT contain the mantissa, either. Consider the following program: #include <iostream> int main(void) { typedef long double FType; FType max= std::numeric_limits<FType>::max(); FType large = 0xA.BCDEF0123456789p+16380L; FType middling = 0xABCDEF01.23456789p0L; long long maxll = max; long long largell = large; long long middlingll = middling; std::cout << std::fixed << "max: " << max << std::endl; std::cout << "large: " << large << std::endl; std::cout << "middling: " << middling << std::endl; std::cout << "maxll: " << maxll << std::endl; std::cout << "largell: " << largell << std::endl; std::cout << "middlingll: " << middlingll << std::endl; std::cout << std::hexfloat << std::showbase << std::showpoint << std::hex << "max: " << max << std::endl; std::cout << "large: " << large << std::endl; std::cout << "middling: " << middling << std::endl; std::cout << "maxll: " << maxll << std::endl; std::cout << "largell: " << largell << std::endl; std::cout << "middlingll: " << middlingll << std::endl; } The output from that program on my system is: max: 118973149535723176502126385303097020516906332229462420044032373389173700552297072261641029033652888285354569780749557731442744315367028843419812557385374367867359320070697326320191591828296152436552951064679108661431179063216977883889613478656060039914875343321145491116008867984515486651285234014977303760000912547939396622315138362241783854274391783813871780588948754057516822634765923557697480511372564902088485522249479139937758502601177354918009979622602685950855888360815984690023564513234659447638493985927645628457966177293040780660922910271504608538808795932778162298682754783076808004015069494230341172895777710033571401055977524212405734700738625166011082837911962300846927720096515350020847447079244384854591288672300061908512647211195136146752763351956292759795725027800298079590419313960302147099703527646744553092202267965628099149823208332964124103850923918473478612192169721054348428704835340811304257300221642134891734717423480071488075100206439051723424765600472176809648610799494 341570347632064355862420744350442438056613601760883747816538902780957697597728686007148702828795556714140463261583262360276289631617397848425448686060994827086796804807870251185893083854658422304090880599629459458620190376604844679092600222541053077590106576067134720012584640695703025713896098375799892695455305236856075868317922311363951946885088077187210470520395758748001314313144425494391994017575316933939236688185618912993172910425292123683515992232205099800167710278403536014082929639811512287776813570604578934353545169653956125404884644716978689321167108722908808277835051822885764606221873970285165508372099234948333443522898475123275372663606621390228126470623407535207172405866507951821730346378263135339370677490195019784169044182473806316282858685774143258116536404021840272491339332094921949842244273042701987304453662035026238695780468200360144729199712309553005720614186697485284685618651483271597448120312194675168637934309618961510733006555242148519520176285859509105183947250286 387163249416761380499631979144187025430270675849519200883791516940158174004671147787720145964446117520405945350476472180797576111172084627363927960033967047003761337450955318415007379641260504792325166135484129188421134082301547330475406707281876350361733290800595189632520707167390454777712968226520622565143991937680440029238090311243791261477625596469422198137514696707944687035800439250765945161837981185939204954403611491531078225107269148697980924094677214272701240437718740921675661363493890045123235166814608932240069799317601780533819184998193300841098599393876029260139091141452600372028487213241195542428210183120421610446740462163533690058366460659115629876474552506814500393294140413149540067760295100596225302282300363147382468105964844244132486457313743759509641616804802412935187620466813563687753281467553879887177183651289394719533506188500326760735438867336800207438784965701457609034985757124304510203873049485425670247933932280911052604153852899484920399109194612991249163328991 799809438033787952209313146694614970593966415237594928589096048991612194498998638483702248667224914892467841020618336462741696957630763248023558797524525373703543388296086275342774001633343405508353704850737454481975472222897528108302089868263302028525992308416805453968791141829762998896457648276528750456285492426516521775079951625966922911497778896235667095662713848201819134832168799586365263762097828507009933729439678463987902491451422274252700636394232799848397673998715441855420156224415492665301451550468548925862027608576183712976335876121538256512963353814166394951655600026415918655485005705261143195291991880795452239464962763563017858089669222640623538289853586759599064700838568712381032959192649484625076899225841930548076362021508902214922052806984201835084058693849381549890944546197789302911357651677540623227829831403347327660395223160342282471752818181884430488092132193355086987339586127607367086665237555567580317149010847732009642431878007000879734603290627894355374356444885 1907191616455141155761939399690767415156402826543664026760095087523945507341556135867933066031744720924446513532366647649735400851967040771103640538150073486891798364049570606189535005089840913826869535090066783324472578712196604415284924840041850932811908963634175739897166596000759487800619164094854338758520657116541072260996288150123144377944008749301944744330784388995701842710004808305012177123560622895076269042856800047718893158089358515593863176652948089031267747029662545110861548958395087796755464137944895960527975209874813839762578592105756284401759349324162148339565350189196811389091843795734703269406342890087805846940352453479398080674273236297887100867175802531561302356064878709259865288416350972529537091114317204887747405539054009425375424119317944175137064689643861517718849867010341532542385911089624710885385808688837777258648564145934262121086647588489260031762345960769508849149662444156604419552086811989770240.000000 large: 798441950131984170628030460666810333557348275190265576078984094186809314595841573532599033606882733242214503184515646114757854809285221996356228289554376635019344753920776702760669187940817514531317086140383510733112508649664623633139528050777110074618005617509580146833305060924324246754342390819803294975489244294690457181615916380846787220310100995994303945777913450178570581981686198498193907782547173273698279385392870067122516401380661309429194377571288675510592121362933128690216937551164723903033967732288194633304806974443077506079764506140348104093213176088240569763532433031309628120758051299847190906531282735560740981504351645262405988024022915769015155291537373039452757287714224413271925722965109196412960233450108997556205354431107378518341642987291604090752426939027264213019440145124490661477726747318914574881469961518134515108880857245240185572718139826633083153405462806445652888413410638188733734515336089461690188769941296000310237908472871534924022605781553137758150233789260 358532907145882036161660126945661711839735421711825178177760957818009605928677177600206353608487447867000007661334384127783042012294562593528684725810884617737609254169149626757295679706675640253674305137724007576430362146351195481618750152400954313053997866464669799426096587456831642162987414724896100262164539763660362382092573961783134501772282908098290593289630152876770300417744973458556470142688766464671575130409003788303712422629946652772747989412570452719563049061781235816001067752251851519827096684941366242307880857459992859988995242358876699073496204946189012116094636726007751024562501070868616158003530658455857341162526439165492140517609950096619412732907944896057390196270057177242728156339638540867610924105857412556444579107776816889674631366413677833047161379884532164198993276772896425495083000505555449504361780772635099950677280195245017300352256591786535445649376601829488196382898175912034787015428923592784580276113369666903167358253633530441611097653596975461248061662339 365488473119600829523500459203619456964603129018988931194328288813647101701632839512858929869478394804296698394260954809692417234406205371106893496236967789991565505735586236384677950809842953217931584749260769959701438782478571501334539385640439880396793372493213016627745357811930479029023541095769455142488296966879072936425173785823423491784831896194556031386766634408387982622337724480135007299914446877152530780342928097086987514633283924856437263144768383859171111988014305350935374816502702333251093923757732462792355307789905174719099488759733393438698689634230361403084258533397265120127568961174111327297320782260488730893216700453978837717137622769084406167566152759623181706028976375164646094475146647369281575972522853549552541720923007665948643646011282736873309526428963407898352464481165847664515121092198236329555997024089181776782273133008347683849048553390800664712980340475996260480072720565715887831207483955807832767939883392425546385536716077432630898214899484281107511073792 175413829068138175373955787942264464985983774969783604562637885180871016551868231242254625289486930794202391413454134460390851822972288028367994924347840148793791361918282891665866879658491796934476927641493412928958649240130825652229115711491817767450106062789615541320400721098889852085898259254162735307793046490526388026316295280894798927076625172952033631816193510840287691268927294098058192308372212486275935018916579164964951401297805003291270040660302706760922674620757844937737189874735833048611876587062084398065184497992254250923170482005379707778025178444614040206924597320627466243597003790395509022310055565959173599974814957486832121747812898110468472757711344935141581619768179027277300745026178548690842027389022573413486719086424376549995531862953495262810743844967518912745788410885417320073667346399372144729172804316265474393461925206370016332837493346298714231599348699028709728862988664452830290361646545475793248617512310081372368799772054350231317371686452672996009981551057 400080425522396446487229356262303917938229664789869208363238136397068893440807223464451417926302339445880535875195702287684615206433710292963594791392187167500246785808792158380039590563187800668321919054700778993223664127005039562879931963775644174414234242371897053417500956186032208506564827824530909432144378661326313617577661894233125412875713957392594237250272900479523399925200381753270457862573831453382693219682510773999798436059405397109340096099851440470543315842651194313580726690246948309173037070102422697928865543593593980166075781220064584748135949528803322043763798528128793152883647487108192854012453988821565817611465474933891481140768062268834838833326673555808237357184051468989117126978502141404852191804301542607646946130977410809967278476698460181222465259056386246982267558528987894457868410385101006422099287064483189598631389250604017773829174392421160930626885766469862665970968575978122938895191153280286720.000000 middling: 2882400001.137778 maxll: 9223372036854775807 largell: 9223372036854775807 middlingll: 2882400001 max: 0xf.fffffffffffffffp+16380 large: 0xa.bcdef0123456789p+16380 middling: 0xa.bcdef0123456789p+28 maxll: 0x7fffffffffffffff largell: 0x7fffffffffffffff middlingll: 0xabcdef01 I'll use hexadecimal notation in the following comments: The whole part of "max" has the same value as "max" itself. The same is true of "large". The whole part of middling is 0xABCDEF01. The fractional part of middling is 0x0.23456789. The mantissas are as follows: max: 0xffffffffffffffff large: 0xabcdef0123456789 middling: 0xabcdef0123456789 The values stored in "maxll" and "largell" do not match either the whole part or the mantissa of the corresponding floating point number. Because "middling" is the only one of the three long double values that is smaller than LLONG_MAX, the value stored in middlingll is the whole part of "middling", as it should be, but is quite different from the mantissa of "middling". |
| "Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Oct 02 09:00PM +0200 On 1 Oct 2021 17:37, wij wrote: > x=::ldexpl(x,numeric_limits<FType>::digits); > mint= static_cast<int64_t>(x); > Result (mint) is a negative number, something not right!!! Apparently you're trying to obtain the bits of the mantissa of a `long double` number, represented as an `int64_t` value. A `long double` is in practice either IEEE 754 64-bit, or IEEE 754 80-bit. In Windows that choice depends on the compiler. With Visual C++ (and hence probably also Intel) it's 64-bit, same as type `double`, while with MinGW g++ (and hence probably also clang) it 80-bit, originally the x86-family's math coprocessor's extended format. For 80-bit IEEE 754 the mantissa part is 64 bits. With 64-bits mantissa there is a high chance of setting the sign bit of an `int64_t` to 1, resulting in a negative value. I believe that that will only /not/ happen for a denormal value, but, I'm tired and might be wrong about that. Anyway, instead use unsigned types for bit handling. For example, in this case, use `uint64_t`. However, instead of the shenanigans with `frexpl` and `ldexpl` I'd just use `memcpy`. Due to the silliness in gcc regarding the standard's "strict aliasing" rule, I'd not use a reinterpretation pointer cast. - Alf |
| James Kuyper <jameskuyper@alumni.caltech.edu>: Oct 02 03:12PM -0400 On 10/2/21 3:00 PM, Alf P. Steinbach wrote: > will only /not/ happen for a denormal value, but, I'm tired and might be > wrong about that. Anyway, instead use unsigned types for bit handling. > For example, in this case, use `uint64_t`. It would be safer and more portable to use FType; there's no portable guarantee that any integer type is large enough to hold the mantissa, but FType is. > However, instead of the shenanigans with `frexpl` and `ldexpl` I'd just > use `memcpy`. The advantage of the code as written is that (if you change mint to have FType) it will give the correct result even if your assumption about IEEE 754 is false; that's not the case with memcpy(). |
| "Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Oct 02 09:23PM +0200 On 2 Oct 2021 21:12, James Kuyper wrote: > It would be safer and more portable to use FType; there's no portable > guarantee that any integer type is large enough to hold the mantissa, > but FType is. I believe you intended to write `uintptr_t`, not `FType`. If so, agreed. It's late in the day for me, sorry. > The advantage of the code as written is that (if you change mint to have > FType) it will give the correct result even if your assumption about > IEEE 754 is false; that's not the case with memcpy(). Uhm, I'd rather assert IEEE 754 representation (numeric_limits::is_iec559). Dealing with the bits of just about any representation seems to me a hopelessly daunting task. :-o - Alf |
| "Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Oct 02 09:27PM +0200 On 2 Oct 2021 21:23, Alf P. Steinbach wrote: > I believe you intended to write `uintptr_t`, not `FType`. > If so, agreed. > It's late in the day for me, sorry. It's /very/ late. There AFAIK is no suitable type name for the integer type with sufficient bits to represent the mantissa, or generally >N bits. Unfortunately the standard library doesn't provide a mapping from number of bits as a value, to integer type with that many bits. It can be done, on the assumption that all types in `<stdint.h>` are present. And perhaps one can then define a name like `FType` in terms of that mapping. |
| James Kuyper <jameskuyper@alumni.caltech.edu>: Oct 02 03:37PM -0400 On 10/2/21 2:59 PM, Branimir Maksimovic wrote: > large for type 'long double'; maximum is 1.7976931348623157E+308 > [-Wliteral-range] > Sorry your program is not correct.. The value of "large" was chosen to be almost as large as "max" on my machine. It's apparently larger than LDBL_MAX on your system. A more portable initializer would be FType large = 0x0.ABCDEF0123456789p0L * max; Depending upon the value of LDBL_EPSILON on the target implementation, that definition might result in the mantissa of "large" having fewer significant digits than it has on mine, but that's not particularly important. > largell: 0x7fffffffffffffff > middlingll: 0xabcdef01 > Greetings, Branimir. With that change, the value of "large" on my machine changes to 0xa.bcdef0123456788p+16380, with a corresponding (HUGE) change to the less significant digits of the decimal output, and the mantissa is therefore 0xabcdef0123456788. You'll get much different values for "max" and "large" on your system, since LDBL_MAX is much smaller, but the qualitative comments I made about those values should still be accurate. There's no guarantees, since the behavior is undefined, but I would expect that the values of "maxll" and "largell" will be unchanged. |
| Manfred <noname@add.invalid>: Oct 02 11:19PM +0200 On 10/2/2021 9:27 PM, Alf P. Steinbach wrote: > It's /very/ late. > There AFAIK is no suitable type name for the integer type with > sufficient bits to represent the mantissa, or generally >N bits. He meant the FType that is in the original post. I.e. the same floating point type of the number to be analyzed. |
| Paavo Helde <myfirstname@osa.pri.ee>: Oct 02 10:57PM +0300 29.09.2021 12:46 Ian Collins kirjutas: >> Writing the string buffer of 418 MB into a disk file: 146 ms > Interesting, thanks for posting. It's a similar ratio on my machine. I > can see that the Windows way of doing things is definitely more burdensome. For curiosity, I also added a non-portable memory map variant to timings. As expected, it beats all the other methods. On Windows it is ca 21 times faster than ostream<<int streaming, on Linux it is just 3 times faster. It preallocates a large file in advance and trims it into the correct size later, it might be one can yet shave off some cycles by doing something smarter. MSVC++ Win x64 Release: Traditional streaming (ostream<<int): 16309 ms Streaming with std::to_chars() directly into streambuf: 1353 ms Collecting the content in a string buffer of 418 MB: 1123 ms Writing the string buffer of 418 MB into a disk file: 668 ms Serializing to memory-mapped file: 753 ms Speedup of mmap, compared to ostream<<int: 21.6587 times Linux g++ 8.3: $ g++ -O3 -std=c++17 test7.cpp $ ./a.out Traditional streaming (ostream<<int): 2358 ms Streaming with std::to_chars() directly into streambuf: 1142 ms Collecting the content in a string buffer of 418 MB: 674 ms Writing the string buffer of 418 MB into a disk file: 393 ms Serializing to memory-mapped file: 772 ms Speedup of mmap, compared to ostream<<int: 3.0544 times #include <iostream> #include <string> #include <vector> #include <numeric> #include <charconv> #include <chrono> #include <cstdint> #include <fstream> #include <limits> #include <stdexcept> #ifdef _WIN32 #define NOMINMAX #include <Windows.h>
Subscribe to:
Post Comments (Atom)
|
No comments:
Post a Comment