Movatterモバイル変換
[0]ホーム
\begin{code}#include "ieee-flpt.h"moduleGHC.Float(moduleGHC.Float,Float(..),Double(..),Float#,Double#,double2Int,int2Double,float2Int,int2Float)whereimportData.MaybeimportData.BitsimportGHC.BaseimportGHC.ListimportGHC.EnumimportGHC.ShowimportGHC.NumimportGHC.RealimportGHC.ArrimportGHC.Float.RealFracMethodsimportGHC.Float.ConversionUtilsimportGHC.Integer.Logarithms(integerLogBase#)importGHC.Integer.Logarithms.Internalsinfixr8**
\end{code}%*********************************************************%* *\subsection{Standard numeric classes}%* *%*********************************************************\begin{code}class(Fractionala)=>Floatingawherepi::aexp,log,sqrt::a->a(**),logBase::a->a->asin,cos,tan::a->aasin,acos,atan::a->asinh,cosh,tanh::a->aasinh,acosh,atanh::a->ax**y=exp(logx*y)logBasexy=logy/logxsqrtx=x**0.5tanx=sinx/cosxtanhx=sinhx/coshxclass(RealFraca,Floatinga)=>RealFloatawherefloatRadix::a->IntegerfloatDigits::a->IntfloatRange::a->(Int,Int)decodeFloat::a->(Integer,Int)encodeFloat::Integer->Int->aexponent::a->Intsignificand::a->ascaleFloat::Int->a->aisNaN::a->BoolisInfinite::a->BoolisDenormalized::a->BoolisNegativeZero::a->BoolisIEEE::a->Boolatan2::a->a->aexponentx=ifm==0then0elsen+floatDigitsxwhere(m,n)=decodeFloatxsignificandx=encodeFloatm(negate(floatDigitsx))where(m,_)=decodeFloatxscaleFloatkx=encodeFloatm(n+clampbk)where(m,n)=decodeFloatx(l,h)=floatRangexd=floatDigitsxb=hl+4*datan2yx|x>0=atan(y/x)|x==0&&y>0=pi/2|x<0&&y>0=pi+atan(y/x)|(x<=0&&y<0)||(x<0&&isNegativeZeroy)||(isNegativeZerox&&isNegativeZeroy)=atan2(y)x|y==0&&(x<0||isNegativeZerox)=pi|x==0&&y==0=y|otherwise=x+y
\end{code}%*********************************************************%* *\subsection{Type @Float@}%* *%*********************************************************\begin{code}instanceNumFloatwhere(+)xy=plusFloatxy()xy=minusFloatxynegatex=negateFloatx(*)xy=timesFloatxyabsx|x>=0.0=x|otherwise=negateFloatxsignumx|x==0.0=0|x>0.0=1|otherwise=negate1fromIntegeri=F#(floatFromIntegeri)instanceRealFloatwheretoRational(F#x#)=casedecodeFloat_Int#x#of(#m#,e##)|e#>=#0#->(smallIntegerm#`shiftLInteger`e#):%1|(int2Word#m#`and#`1##)`eqWord#`0##->caseelimZerosInt#m#(negateInt#e#)of(#n,d##)->n:%shiftLInteger1d#|otherwise->smallIntegerm#:%shiftLInteger1(negateInt#e#)instanceFractionalFloatwhere(/)xy=divideFloatxyfromRational(n:%0)|n==0=0/0|n<0=(1)/0|otherwise=1/0fromRational(n:%d)|n==0=encodeFloat00|n<0=(fromRat''minExmantDigs(n)d)|otherwise=fromRat''minExmantDigsndwhereminEx=FLT_MIN_EXPmantDigs=FLT_MANT_DIGrecipx=1.0/xinstanceRealFracFloatwhere#if FLT_RADIX != 2#error FLT_RADIX must be 2#endifproperFraction(F#x#)=casedecodeFloat_Int#x#of(#m#,n##)->letm=I#m#n=I#n#inifn>=0then(fromIntegralm*(2^n),0.0)elseleti=ifm>=0thenm`shiftR`negatenelsenegate(negatem`shiftR`negaten)f=m(i`shiftL`negaten)in(fromIntegrali,encodeFloat(fromIntegralf)n)truncatex=caseproperFractionxof(n,_)->nroundx=caseproperFractionxof(n,r)->letm=ifr<0.0thenn1elsen+1half_down=absr0.5incase(comparehalf_down0.0)ofLT->nEQ->ifevennthennelsemGT->mceilingx=caseproperFractionxof(n,r)->ifr>0.0thenn+1elsenfloorx=caseproperFractionxof(n,r)->ifr<0.0thenn1elseninstanceFloatingFloatwherepi=3.141592653589793238expx=expFloatxlogx=logFloatxsqrtx=sqrtFloatxsinx=sinFloatxcosx=cosFloatxtanx=tanFloatxasinx=asinFloatxacosx=acosFloatxatanx=atanFloatxsinhx=sinhFloatxcoshx=coshFloatxtanhx=tanhFloatx(**)xy=powerFloatxylogBasexy=logy/logxasinhx=log(x+sqrt(1.0+x*x))acoshx=log(x+(x+1.0)*sqrt((x1.0)/(x+1.0)))atanhx=0.5*log((1.0+x)/(1.0x))instanceRealFloatFloatwherefloatRadix_=FLT_RADIXfloatDigits_=FLT_MANT_DIGfloatRange_=(FLT_MIN_EXP,FLT_MAX_EXP)decodeFloat(F#f#)=casedecodeFloat_Int#f#of(#i,e#)->(smallIntegeri,I#e)encodeFloati(I#e)=F#(encodeFloatIntegerie)exponentx=casedecodeFloatxof(m,n)->ifm==0then0elsen+floatDigitsxsignificandx=casedecodeFloatxof(m,_)->encodeFloatm(negate(floatDigitsx))scaleFloatkx=casedecodeFloatxof(m,n)->encodeFloatm(n+clampbfk)wherebf=FLT_MAX_EXP(FLT_MIN_EXP)+4*FLT_MANT_DIGisNaNx=0/=isFloatNaNxisInfinitex=0/=isFloatInfinitexisDenormalizedx=0/=isFloatDenormalizedxisNegativeZerox=0/=isFloatNegativeZeroxisIEEE_=TrueinstanceShowFloatwhereshowsPrecx=showSignedFloatshowFloatxshowList=showList__(showsPrec0)
\end{code}%*********************************************************%* *\subsection{Type @Double@}%* *%*********************************************************\begin{code}instanceNumDoublewhere(+)xy=plusDoublexy()xy=minusDoublexynegatex=negateDoublex(*)xy=timesDoublexyabsx|x>=0.0=x|otherwise=negateDoublexsignumx|x==0.0=0|x>0.0=1|otherwise=negate1fromIntegeri=D#(doubleFromIntegeri)instanceRealDoublewheretoRational(D#x#)=casedecodeDoubleIntegerx#of(#m,e##)|e#>=#0#->shiftLIntegerme#:%1|(int2Word#(integerToIntm)`and#`1##)`eqWord#`0##->caseelimZerosIntegerm(negateInt#e#)of(#n,d##)->n:%shiftLInteger1d#|otherwise->m:%shiftLInteger1(negateInt#e#)instanceFractionalDoublewhere(/)xy=divideDoublexyfromRational(n:%0)|n==0=0/0|n<0=(1)/0|otherwise=1/0fromRational(n:%d)|n==0=encodeFloat00|n<0=(fromRat''minExmantDigs(n)d)|otherwise=fromRat''minExmantDigsndwhereminEx=DBL_MIN_EXPmantDigs=DBL_MANT_DIGrecipx=1.0/xinstanceFloatingDoublewherepi=3.141592653589793238expx=expDoublexlogx=logDoublexsqrtx=sqrtDoublexsinx=sinDoublexcosx=cosDoublextanx=tanDoublexasinx=asinDoublexacosx=acosDoublexatanx=atanDoublexsinhx=sinhDoublexcoshx=coshDoublextanhx=tanhDoublex(**)xy=powerDoublexylogBasexy=logy/logxasinhx=log(x+sqrt(1.0+x*x))acoshx=log(x+(x+1.0)*sqrt((x1.0)/(x+1.0)))atanhx=0.5*log((1.0+x)/(1.0x))instanceRealFracDoublewhereproperFractionx=case(decodeFloatx)of{(m,n)->ifn>=0then(fromIntegerm*2^n,0.0)elsecase(quotRemm(2^(negaten)))of{(w,r)->(fromIntegerw,encodeFloatrn)}}truncatex=caseproperFractionxof(n,_)->nroundx=caseproperFractionxof(n,r)->letm=ifr<0.0thenn1elsen+1half_down=absr0.5incase(comparehalf_down0.0)ofLT->nEQ->ifevennthennelsemGT->mceilingx=caseproperFractionxof(n,r)->ifr>0.0thenn+1elsenfloorx=caseproperFractionxof(n,r)->ifr<0.0thenn1elseninstanceRealFloatDoublewherefloatRadix_=FLT_RADIXfloatDigits_=DBL_MANT_DIGfloatRange_=(DBL_MIN_EXP,DBL_MAX_EXP)decodeFloat(D#x#)=casedecodeDoubleIntegerx#of(#i,j#)->(i,I#j)encodeFloati(I#j)=D#(encodeDoubleIntegerij)exponentx=casedecodeFloatxof(m,n)->ifm==0then0elsen+floatDigitsxsignificandx=casedecodeFloatxof(m,_)->encodeFloatm(negate(floatDigitsx))scaleFloatkx=casedecodeFloatxof(m,n)->encodeFloatm(n+clampbdk)wherebd=DBL_MAX_EXP(DBL_MIN_EXP)+4*DBL_MANT_DIGisNaNx=0/=isDoubleNaNxisInfinitex=0/=isDoubleInfinitexisDenormalizedx=0/=isDoubleDenormalizedxisNegativeZerox=0/=isDoubleNegativeZeroxisIEEE_=TrueinstanceShowDoublewhereshowsPrecx=showSignedFloatshowFloatxshowList=showList__(showsPrec0)\end{code}%*********************************************************%* *\subsection{@Enum@ instances}%* *%*********************************************************The @Enum@ instances for Floats and Doubles are slightly unusual.The @toEnum@ function truncates numbers to Int. The definitionsof @enumFrom@ and @enumFromThen@ allow floats to be used in arithmeticseries: [0,0.1 .. 1.0]. However, roundoff errors make these somewhatdubious. This example may have either 10 or 11 elements, depending onhow 0.1 is represented.NOTE: The instances for Float and Double do not make use of the defaultmethods for @enumFromTo@ and @enumFromThenTo@, as these rely on there beinga `non-lossy' conversion to and from Ints. Instead we make use of the1.2 default methods (back in the days when Enum had Ord as a superclass)for these (@numericEnumFromTo@ and @numericEnumFromThenTo@ below.)\begin{code}instanceEnumFloatwheresuccx=x+1predx=x1toEnum=int2FloatfromEnum=fromInteger.truncateenumFrom=numericEnumFromenumFromTo=numericEnumFromToenumFromThen=numericEnumFromThenenumFromThenTo=numericEnumFromThenToinstanceEnumDoublewheresuccx=x+1predx=x1toEnum=int2DoublefromEnum=fromInteger.truncateenumFrom=numericEnumFromenumFromTo=numericEnumFromToenumFromThen=numericEnumFromThenenumFromThenTo=numericEnumFromThenTo
\end{code}%*********************************************************%* *\subsection{Printing floating point}%* *%*********************************************************\begin{code}showFloat::(RealFloata)=>a->ShowSshowFloatx=showString(formatRealFloatFFGenericNothingx)dataFFFormat=FFExponent|FFFixed|FFGenericformatRealFloat::(RealFloata)=>FFFormat->MaybeInt->a->StringformatRealFloatfmtdecsx|isNaNx="NaN"|isInfinitex=ifx<0then"-Infinity"else"Infinity"|x<0||isNegativeZerox='-':doFmtfmt(floatToDigits(toIntegerbase)(x))|otherwise=doFmtfmt(floatToDigits(toIntegerbase)x)wherebase=10doFmtformat(is,e)=letds=mapintToDigitisincaseformatofFFGeneric->doFmt(ife<0||e>7thenFFExponentelseFFFixed)(is,e)FFExponent->casedecsofNothing->letshow_e'=show(e1)incasedsof"0"->"0.0e0"[d]->d:".0e"++show_e'(d:ds')->d:'.':ds'++"e"++show_e'[]->error"formatRealFloat/doFmt/FFExponent: []"Justdec->letdec'=maxdec1incaseisof[0]->'0':'.':takedec'(repeat'0')++"e0"_->let(ei,is')=roundTobase(dec'+1)is(d:ds')=mapintToDigit(ifei>0theninitis'elseis')ind:'.':ds'++'e':show(e1+ei)FFFixed->letmk0ls=caselsof{""->"0";_->ls}incasedecsofNothing|e<=0->"0."++replicate(e)'0'++ds|otherwise->letf0srs=mk0(reverses)++'.':mk0rsfns""=f(n1)('0':s)""fns(r:rs)=f(n1)(r:s)rsinfe""dsJustdec->letdec'=maxdec0inife>=0thenlet(ei,is')=roundTobase(dec'+e)is(ls,rs)=splitAt(e+ei)(mapintToDigitis')inmk0ls++(ifnullrsthen""else'.':rs)elselet(ei,is')=roundTobasedec'(replicate(e)0++is)d:ds'=mapintToDigit(ifei>0thenis'else0:is')ind:(ifnullds'then""else'.':ds')roundTo::Int->Int->[Int]->(Int,[Int])roundTobasedis=casefdisofx@(0,_)->x(1,xs)->(1,1:xs)_->error"roundTo: bad Value"whereb2=base`div`2fn[]=(0,replicaten0)f0(x:_)=(ifx>=b2then1else0,[])fn(i:xs)|i'==base=(1,0:ds)|otherwise=(0,i':ds)where(c,ds)=f(n1)xsi'=c+ifloatToDigits::(RealFloata)=>Integer->a->([Int],Int)floatToDigits_0=([0],0)floatToDigitsbasex=let(f0,e0)=decodeFloatx(minExp0,_)=floatRangexp=floatDigitsxb=floatRadixxminExp=minExp0p(f,e)=letn=minExpe0inifn>0then(f0`quot`(exptbn),e0+n)else(f0,e0)(r,s,mUp,mDn)=ife>=0thenletbe=exptbeiniff==exptb(p1)then(f*be*b*2,2*b,be*b,be)else(f*be*2,2,be,be)elseife>minExp&&f==exptb(p1)then(f*b*2,exptb(e+1)*2,b,1)else(f*2,exptb(e)*2,1,1)k::Intk=letk0::Intk0=ifb==2&&base==10thenletlx=p1+e0k1=(lx*8651)`quot`28738iniflx>=0thenk1+1elsek1elseceiling((log(fromInteger(f+1)::Float)+fromIntegrale*log(fromIntegerb))/log(fromIntegerbase))fixupn=ifn>=0thenifr+mUp<=exptbasen*sthennelsefixup(n+1)elseifexptbase(n)*(r+mUp)<=sthennelsefixup(n+1)infixupk0gendsrnsNmUpNmDnN=let(dn,rn')=(rn*base)`quotRem`sNmUpN'=mUpN*basemDnN'=mDnN*baseincase(rn'<mDnN',rn'+mUpN'>sN)of(True,False)->dn:ds(False,True)->dn+1:ds(True,True)->ifrn'*2<sNthendn:dselsedn+1:ds(False,False)->gen(dn:ds)rn'sNmUpN'mDnN'rds=ifk>=0thengen[]r(s*exptbasek)mUpmDnelseletbk=exptbase(k)ingen[](r*bk)s(mUp*bk)(mDn*bk)in(mapfromIntegral(reverserds),k)\end{code}%*********************************************************%* *\subsection{Converting from a Rational to a RealFloat%* *%*********************************************************[In response to a request for documentation of how fromRational works,Joe Fasel writes:] A quite reasonable request! This code was added tothe Prelude just before the 1.2 release, when Lennart, working with anearly version of hbi, noticed that (read . show) was not the identityfor floating-point numbers. (There was a one-bit error about half thetime.) The original version of the conversion function was in factsimply a floating-point divide, as you suggest above. The new versionis, I grant you, somewhat denser.Unfortunately, Joe's code doesn't work! Here's an example:main = putStr (shows (1.82173691287639817263897126389712638972163e-300::Double) "\n")This program prints 0.0000000000000000instead of 1.8217369128763981e-300Here's Joe's code:\begin{pseudocode}fromRat :: (RealFloat a) => Rational -> afromRat x = x' where x' = f e-- If the exponent of the nearest floating-point number to x-- is e, then the significand is the integer nearest xb^(-e),-- where b is the floating-point radix. We start with a good-- guess for e, and if it is correct, the exponent of the-- floating-point number we construct will again be e. If-- not, one more iteration is needed. f e = if e' == e then y else f e' where y = encodeFloat (round (x * (1 % b)^^e)) e (_,e') = decodeFloat y b = floatRadix x'-- We obtain a trial exponent by doing a floating-point-- division of x's numerator by its denominator. The-- result of this division may not itself be the ultimate-- result, because of an accumulation of three rounding-- errors. (s,e) = decodeFloat (fromInteger (numerator x) `asTypeOf` x' / fromInteger (denominator x))\end{pseudocode}Now, here's Lennart's code (which works)\begin{code}fromRat::(RealFloata)=>Rational->afromRat(n:%0)|n>0=1/0|n<0=1/0|otherwise=0/0fromRat(n:%d)|n>0=fromRat'(n:%d)|n<0=fromRat'((n):%d)|otherwise=encodeFloat00fromRat'::(RealFloata)=>Rational->afromRat'x=rwhereb=floatRadixrp=floatDigitsr(minExp0,_)=floatRangerminExp=minExp0pxMin=toRational(exptb(p1))xMax=toRational(exptbp)p0=(integerLogBaseb(numeratorx)integerLogBaseb(denominatorx)p)`max`minExpf=ifp0<0then1%exptb(p0)elseexptbp0%1(x',p')=scaleRat(toRationalb)minExpxMinxMaxp0(x/f)r=encodeFloat(roundx')p'scaleRat::Rational->Int->Rational->Rational->Int->Rational->(Rational,Int)scaleRatbminExpxMinxMaxpx|p<=minExp=(x,p)|x>=xMax=scaleRatbminExpxMinxMax(p+1)(x/b)|x<xMin=scaleRatbminExpxMinxMax(p1)(x*b)|otherwise=(x,p)minExpt,maxExpt::IntminExpt=0maxExpt=1100expt::Integer->Int->Integerexptbasen=ifbase==2&&n>=minExpt&&n<=maxExptthenexpts!nelseifbase==10&&n<=maxExpt10thenexpts10!nelsebase^nexpts::ArrayIntIntegerexpts=array(minExpt,maxExpt)[(n,2^n)|n<-[minExpt..maxExpt]]maxExpt10::IntmaxExpt10=324expts10::ArrayIntIntegerexpts10=array(minExpt,maxExpt10)[(n,10^n)|n<-[minExpt..maxExpt10]]integerLogBase::Integer->Integer->IntintegerLogBasebi|i<b=0|b==2=I#(integerLog2#i)|otherwise=I#(integerLogBase#bi)
\end{code}Unfortunately, the old conversion code was awfully slow due toa) a slow integer logarithmb) repeated calculation of gcd'sFor the case of Rational's coming from a Float or Double via toRational,we can exploit the fact that the denominator is a power of two, which forthese brings a huge speedup since we need only shift and add insteadof division.The below is an adaption of fromRat' for the conversion toFloat or Double exploiting the know floatRadix and avoidingdivisions as much as possible.\begin{code}fromRat''::RealFloata=>Int->Int->Integer->Integer->afromRat''minEx@(I#me#)mantDigs@(I#md#)nd=caseintegerLog2IsPowerOf2#dof(#ld#,pw##)|pw#==#0#->caseintegerLog2#nofln#|ln#>#(ld#+#me#)->ifln#<#md#thenencodeFloat(n`shiftL`(I#(md#-#1#-#ln#)))(I#(ln#+#1#-#ld#-#md#))elseletn'=n`shiftR`(I#(ln#+#1#-#md#))n''=caseroundingMode#n(ln#-#md#)of0#->n'2#->n'+1_->casefromIntegern'.&.(1::Int)of0->n'_->n'+1inencodeFloatn''(I#(ln#-#ld#+#1#-#md#))|otherwise->caseld#+#(me#-#md#)ofld'#|ld'#>#(ln#+#1#)->encodeFloat00|ld'#==#(ln#+#1#)->caseintegerLog2IsPowerOf2#nof(#_,0##)->encodeFloat00(#_,_#)->encodeFloat1(minExmantDigs)|ld'#<=#0#->encodeFloatn(I#((me#-#md#)-#ld'#))|otherwise->letn'=n`shiftR`(I#ld'#)incaseroundingMode#n(ld'#-#1#)of0#->encodeFloatn'(minExmantDigs)1#->iffromIntegern'.&.(1::Int)==0thenencodeFloatn'(minExmantDigs)elseencodeFloat(n'+1)(minExmantDigs)_->encodeFloat(n'+1)(minExmantDigs)|otherwise->letln=I#(integerLog2#n)ld=I#ld#p0=maxminEx(lnld)(n',d')|p0<mantDigs=(n`shiftL`(mantDigsp0),d)|p0==mantDigs=(n,d)|otherwise=(n,d`shiftL`(p0mantDigs))scalepab|p<=minExmantDigs=(p,a,b)|a<(b`shiftL`(mantDigs1))=(p1,a`shiftL`1,b)|(b`shiftL`mantDigs)<=a=(p+1,a,b`shiftL`1)|otherwise=(p,a,b)(p',n'',d'')=scale(p0mantDigs)n'd'rdq=casen''`quotRem`d''of(q,r)->casecompare(r`shiftL`1)d''ofLT->qEQ->iffromIntegerq.&.(1::Int)==0thenqelseq+1GT->q+1inencodeFloatrdqp'
\end{code}%*********************************************************%* *\subsection{Floating point numeric primops}%* *%*********************************************************Definitions of the boxed PrimOps; these will beused in the case of partial applications, etc.\begin{code}plusFloat,minusFloat,timesFloat,divideFloat::Float->Float->FloatplusFloat(F#x)(F#y)=F#(plusFloat#xy)minusFloat(F#x)(F#y)=F#(minusFloat#xy)timesFloat(F#x)(F#y)=F#(timesFloat#xy)divideFloat(F#x)(F#y)=F#(divideFloat#xy)negateFloat::Float->FloatnegateFloat(F#x)=F#(negateFloat#x)gtFloat,geFloat,eqFloat,neFloat,ltFloat,leFloat::Float->Float->BoolgtFloat(F#x)(F#y)=gtFloat#xygeFloat(F#x)(F#y)=geFloat#xyeqFloat(F#x)(F#y)=eqFloat#xyneFloat(F#x)(F#y)=neFloat#xyltFloat(F#x)(F#y)=ltFloat#xyleFloat(F#x)(F#y)=leFloat#xyexpFloat,logFloat,sqrtFloat::Float->FloatsinFloat,cosFloat,tanFloat::Float->FloatasinFloat,acosFloat,atanFloat::Float->FloatsinhFloat,coshFloat,tanhFloat::Float->FloatexpFloat(F#x)=F#(expFloat#x)logFloat(F#x)=F#(logFloat#x)sqrtFloat(F#x)=F#(sqrtFloat#x)sinFloat(F#x)=F#(sinFloat#x)cosFloat(F#x)=F#(cosFloat#x)tanFloat(F#x)=F#(tanFloat#x)asinFloat(F#x)=F#(asinFloat#x)acosFloat(F#x)=F#(acosFloat#x)atanFloat(F#x)=F#(atanFloat#x)sinhFloat(F#x)=F#(sinhFloat#x)coshFloat(F#x)=F#(coshFloat#x)tanhFloat(F#x)=F#(tanhFloat#x)powerFloat::Float->Float->FloatpowerFloat(F#x)(F#y)=F#(powerFloat#xy)plusDouble,minusDouble,timesDouble,divideDouble::Double->Double->DoubleplusDouble(D#x)(D#y)=D#(x+##y)minusDouble(D#x)(D#y)=D#(x-##y)timesDouble(D#x)(D#y)=D#(x*##y)divideDouble(D#x)(D#y)=D#(x/##y)negateDouble::Double->DoublenegateDouble(D#x)=D#(negateDouble#x)gtDouble,geDouble,eqDouble,neDouble,leDouble,ltDouble::Double->Double->BoolgtDouble(D#x)(D#y)=x>##ygeDouble(D#x)(D#y)=x>=##yeqDouble(D#x)(D#y)=x==##yneDouble(D#x)(D#y)=x/=##yltDouble(D#x)(D#y)=x<##yleDouble(D#x)(D#y)=x<=##ydouble2Float::Double->Floatdouble2Float(D#x)=F#(double2Float#x)float2Double::Float->Doublefloat2Double(F#x)=D#(float2Double#x)expDouble,logDouble,sqrtDouble::Double->DoublesinDouble,cosDouble,tanDouble::Double->DoubleasinDouble,acosDouble,atanDouble::Double->DoublesinhDouble,coshDouble,tanhDouble::Double->DoubleexpDouble(D#x)=D#(expDouble#x)logDouble(D#x)=D#(logDouble#x)sqrtDouble(D#x)=D#(sqrtDouble#x)sinDouble(D#x)=D#(sinDouble#x)cosDouble(D#x)=D#(cosDouble#x)tanDouble(D#x)=D#(tanDouble#x)asinDouble(D#x)=D#(asinDouble#x)acosDouble(D#x)=D#(acosDouble#x)atanDouble(D#x)=D#(atanDouble#x)sinhDouble(D#x)=D#(sinhDouble#x)coshDouble(D#x)=D#(coshDouble#x)tanhDouble(D#x)=D#(tanhDouble#x)powerDouble::Double->Double->DoublepowerDouble(D#x)(D#y)=D#(x**##y)
\end{code}\begin{code}foreignimportccallunsafe"isFloatNaN"isFloatNaN::Float->Intforeignimportccallunsafe"isFloatInfinite"isFloatInfinite::Float->Intforeignimportccallunsafe"isFloatDenormalized"isFloatDenormalized::Float->Intforeignimportccallunsafe"isFloatNegativeZero"isFloatNegativeZero::Float->Intforeignimportccallunsafe"isDoubleNaN"isDoubleNaN::Double->Intforeignimportccallunsafe"isDoubleInfinite"isDoubleInfinite::Double->Intforeignimportccallunsafe"isDoubleDenormalized"isDoubleDenormalized::Double->Intforeignimportccallunsafe"isDoubleNegativeZero"isDoubleNegativeZero::Double->Int
\end{code}%*********************************************************%* *\subsection{Coercion rules}%* *%*********************************************************\begin{code}
\end{code}Note [realToFrac int-to-float]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Don found that the RULES for realToFrac/Int->Double and simliarlyFloat made a huge difference to some stream-fusion programs. Here'san example import Data.Array.Vector n = 40000000 main = do let c = replicateU n (2::Double) a = mapU realToFrac (enumFromToU 0 (n-1) ) :: UArr Double print (sumU (zipWithU (*) c a))Without the RULE we get this loop body: case $wtoRational sc_sY4 of ww_aM7 { (# ww1_aM9, ww2_aMa #) -> case $wfromRat ww1_aM9 ww2_aMa of tpl_X1P { D# ipv_sW3 -> Main.$s$wfold (+# sc_sY4 1) (+# wild_X1i 1) (+## sc2_sY6 (*## 2.0 ipv_sW3))And with the rule: Main.$s$wfold (+# sc_sXT 1) (+# wild_X1h 1) (+## sc2_sXV (*## 2.0 (int2Double# sc_sXT)))The running time of the program goes from 120 seconds to 0.198 secondswith the native backend, and 0.143 seconds with the C backend.A few more details in Trac #2251, and the patch message"Add RULES for realToFrac from Int".%*********************************************************%* *\subsection{Utils}%* *%*********************************************************\begin{code}showSignedFloat::(RealFloata)=>(a->ShowS)->Int->a->ShowSshowSignedFloatshowPospx|x<0||isNegativeZerox=showParen(p>6)(showChar'-'.showPos(x))|otherwise=showPosx
\end{code}We need to prevent over/underflow of the exponent in encodeFloat whencalled from scaleFloat, hence we clamp the scaling parameter.We must have a large enough range to cover the maximum difference ofexponents returned by decodeFloat.\begin{code}clamp::Int->Int->Intclampbdk=max(bd)(minbdk)
\end{code}
[8]ページ先頭