Code Comments
Programming Forum and web based access to our favorite programming groups.Need to detect when a (real 8) number changes sign. Seems the most efficient way should be to test the bit that defines whether the number is pos or neg? However, all the BIT funtiions (apart from TRANSFER) seem to operate only on integers. Surely there is a way to extract the bit that sets +/- for a real number. My current code is along the lines (a = real 8) DO i = 2,n if(a(i)*a(i-1) > 0.d0) CYCLE ! say 90% of cases ... do some minor stuff (one statement) END DO That requires a real*real & i-1 operation for every case. I can use SIGN, but in timinig tests that worked out a lot slower than the current code. If they were integer(8) numbers, the test I envisage would be along the lines: logical(1) no_change integer(8) num(:) integer(4) i, n ALLOCATE( num( ...) ) no_change = BTEST (num(1), 63) DO i = 2,n if( BTEST (num(i), 63) == no_change) CYCLE no_change = .NOT.no_change ... do some stuff END DO Anything equivalent I could use for real numbers? David
Post Follow-up to this message<dud_address@xparadise.net.nz> wrote in message news:u9j5i0l40udqrbl0nt5qrcq8lgu1nv2u0m@ 4ax.com... > DO i = 2,n > if(a(i)*a(i-1) > 0.d0) CYCLE ! say 90% of cases > .... do some minor stuff (one statement) > END DO > That requires a real*real & i-1 operation for every case. Floating point multiplication is cheap or even free on modern processors. Heck, I even wrote some assembly code once for a 21164 which used the floating point multiplier to emulate integer addition, and this actually made the code run faster! On processors with a fully- pipelined floating point multiplier like an Alpha or an Athlon, floating point multiplication is more often than not free. I just finished my Fortran convolution code generator (see my website) and the last thing I worried about was the cost of floating point multiplications, although I minimized their number when doing so didn't cause an increase in the count of floating point additions. Swizzling floating point numbers through the integer register file is kind of an old-fashioned trick that normally leads to slower code on current processors. In your case you might be able to get things to go faster by doing so because this is one of the rare cases where floating point multiplications outnumber other operations. This would be easy in assembly, but in Fortran you would have to either be able to EQUIVALENCE the floating point array to an integer array or use TRANSFER to move a bitwise copy of the floating point variable into an integer variable. Then, assuming no D_FLOAT or G_FLOAT variables, you would test the high bit of the integer as before. -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
Post Follow-up to this messagedud_address@xparadise.net.nz wrote: > Need to detect when a (real 8) number changes sign. Seems the most > efficient way should be to test the bit that defines whether the > number is pos or neg? However, all the BIT funtiions (apart from > TRANSFER) seem to operate only on integers. Surely there is a way to > extract the bit that sets +/- for a real number. > > My current code is along the lines (a = real 8) > > > DO i = 2,n > if(a(i)*a(i-1) > 0.d0) CYCLE ! say 90% of cases How about : if( (a(i)>0.d0) .EQV. (a(i-1)>0.do) ) CYCLE > .... do some minor stuff (one statement) > END DO > No bit twiddling required, thus portable. You may or may not improve on it by saving the result of (a(i)>0.d0) in a logical variable and use that instead of (a(i-1)>0.do) in the next iteration. > > That requires a real*real & i-1 operation for every case. > Only a test can tell whether any of this is really faster than a multiplication on your machine. -- Klaus Wacker wacker@Physik.Uni-Dortmund.DE Experimentelle Physik V http://www.physik.uni-dortmund.de/~wacker Universitaet Dortmund Tel.: +49 231 755 3587 D-44221 Dortmund Fax: +49 231 755 4547
Post Follow-up to this messageOn Wed, 18 Aug 2004 06:03:41 GMT, "James Van Buskirk" <not_valid@comcast.net> wrote: ><dud_address@xparadise.net.nz> wrote in message > news:u9j5i0l40udqrbl0nt5qrcq8lgu1nv2u0m@ 4ax.com... > > > ..... > .......... On processors with a fully- >pipelined floating point multiplier like an Alpha or an >Athlon, floating point multiplication is more often than >not free. ....... >This would be easy in assembly, but in Fortran you would >have to either be able to EQUIVALENCE the floating point >array to an integer array or use TRANSFER to move a >bitwise copy of the floating point variable into an integer >variable. Then, assuming no D_FLOAT or G_FLOAT variables, >you would test the high bit of the integer as before. James & Klaus - many thanks I have now conceded defeat! EQUIVALENCE worked fine, but unfortunately my "a(i)" is actually "gn(i,k)-yg" where yg varies on different walks through this part of the code, so I need an extra line "gn8 = gn(i,k)-yg" before the test, where gn8 is equivalenced to in8. Resulting code is gn8 = gn(1,k)-yg no_change = BTEST (in8, 63) DO i = 2,n gn8 = gn(i,k)-yg ! ### the "killer" ? ### if( BTEST (in8, 63) == no_change) CYCLE no_change = .NOT.no_change ... do some stuff END DO Because this adds an extra real8 subtraction in every case, it is about 40% slower than my original version; ie: if((gn(i,k)-yg)*(gn(i-1,k)-yg) > 0.d0) CYCLE Similarly for Klaus's suggestion - that was also c. 40% slower. I revised my code using SIGN to parallel my original BTEST example (originally I used 2 SIGN's each cycle!). ie revised version: real(8) is_same .... is_same = SIGN(1.0, gn(1,k)-yg) DO i = 2,n if( SIGN(1.0, gn(i,k)-yg) == is_same) CYCLE is_same = -is_same ...... Still took 25% longer than my original real*real option. I never managed to get the TRANSFER option to work - even after I got my facts straight about the locations of the sign bit in real & integer values (my other post) !!! I found a couple of other posts re abysmal performance of TRANSFER so I see no point in pursuing that further. Looks like James' comments about near zero cost of real multiplication might be close to the mark ** (my tests run on an Athlon / IVF8 system). ############ It did seem though, that without the extra line of code the BTEST option could potentially be the fastest. Seems a pity that there is not an equivalent Bit operator for reals, even if restricted solely to testing the sign bit. Perhaps BTEST could be extended to testing the sign bit of a real variable. Bit testing for +/- of a real seems a worthwhile exception that should be easy (?) to implement. Or perhaps "in source" assembly code should be permitted? The performance of SIGN is fairly disappointing (at least in IVF8). David ############ ** I actually tried about 3 variations of the real*real code & they consistently resulted in the same CPU time, despite apparent difference in the work done; eg. two of these were: DO i = 2,n if((gn(i,k)-yg)*(gn(i-1,k)-yg) > 0.d0) CYCLE .... and sign0 = SIGN(1.0, gn(1,k)-yg) DO i = 2,n if((gn(i,k)-yg)*sign0 > 0.d0) CYCLE sign0 = -sign0 .... which eliminates the "(gn(i-1,k)-yg)" subtraction, but has minimal impact on the CPU time. Looks like the above two options are hitting rock bottom CPU time-wise.
Post Follow-up to this messageOn Thu, 19 Aug 2004 00:47:39 +1200, dud_address@xparadise.net.nz wrote: ..... > >** I actually tried about 3 variations of the real*real code & they >consistently resulted in the same CPU time, despite apparent >difference in the work done; eg. two of these were: > >DO i = 2,n > if((gn(i,k)-yg)*(gn(i-1,k)-yg) > 0.d0) CYCLE > ..... > >and > >sign0 = SIGN(1.0, gn(1,k)-yg) >DO i = 2,n > if((gn(i,k)-yg)*sign0 > 0.d0) CYCLE > sign0 = -sign0 > ..... > >which eliminates the "(gn(i-1,k)-yg)" subtraction, but has minimal >impact on the CPU time. > >Looks like the above two options are hitting rock bottom CPU >time-wise. In fact, under repeated testing, the second option does show a slight performance gain ( 0 to 10%) over the first. D
Post Follow-up to this messagedud_address@xparadise.net.nz writes: > Looks like James' comments about near zero cost of real multiplication > might be close to the mark ** Yep. James is almost always worth listening to. I've been "doing" computers for 35 years now and I've learned a lesson that many have also learned before me: some things change. Although there are certainly enduring principles, details like "floating point operations are expensive" aren't among them. Floating point used to be such a big deal that you'd often see performance figures expressed in FLOPS (floating point operations per second). Well, you still see it, but it just doesn't mean as much any more. Memory access seems to be one of the big factors today. Tomorrow maybe something different. That's one of the factors that drives my interest in standards. With fair regularity, younger folk at Dryden are surprised when I start advocating something different from what I did before. Sometimes the older ones are surprised also, but if so, it is because they've forgotten all the previous times I also changed positions. No, I no longer think that a CDC mainframe is the best choice for our engineering applications; that's a postion that I held pretty strongly in the mid 70's. My most recent change was to break down and buy ATA disks instead of SCSI ones for desktops. I won't care about the better performance of the fast SCSI disks if I can't hear any more because of their darned noise level; I can buy some pretty quiet ATA ones. My priorities for system requirements have changed. -- Richard Maine | Good judgment comes from experience; email: my first.last at org.domain | experience comes from bad judgment. org: nasa, domain: gov | -- Mark Twain
Post Follow-up to this messageRichard Maine wrote: > dud_address@xparadise.net.nz writes: > > > > > Yep. James is almost always worth listening to. > > I've been "doing" computers for 35 years now and I've learned a > lesson that many have also learned before me: some things change. > Although there are certainly enduring principles, details like > "floating point operations are expensive" aren't among them. > Floating point used to be such a big deal that you'd often see > performance figures expressed in FLOPS (floating point operations > per second). Well, you still see it, but it just doesn't mean > as much any more. Memory access seems to be one of the big > factors today. Tomorrow maybe something different. > > That's one of the factors that drives my interest in standards. > > With fair regularity, younger folk at Dryden are surprised when I > start advocating something different from what I did before. > Sometimes the older ones are surprised also, but if so, it is > because they've forgotten all the previous times I also changed > positions. No, I no longer think that a CDC mainframe is the > best choice for our engineering applications; that's a postion > that I held pretty strongly in the mid 70's. > > My most recent change was to break down and buy ATA disks instead of > SCSI ones for desktops. I won't care about the better performance of > the fast SCSI disks if I can't hear any more because of their darned > noise level; I can buy some pretty quiet ATA ones. My priorities for > system requirements have changed. > Surely in another 10 years or so, Father Time will have cured your problem hearing noisy disks? *ducks* cheers, Rich -- Dr Richard H D Townsend Bartol Research Institute University of Delaware [ Delete VOID for valid email address ]
Post Follow-up to this messageRich Townsend <rhdt@barVOIDtol.udel.edu> writes: > Surely in another 10 years or so, Father Time will have cured your > problem hearing noisy disks? Eh? :-) > *ducks* Quack. :-) -- Richard Maine | Good judgment comes from experience; email: my first.last at org.domain | experience comes from bad judgment. org: nasa, domain: gov | -- Mark Twain
Post Follow-up to this messagedud_address@xparadise.net.nz wrote in message news:<u9j5i0l40udqrbl0nt5qrcq8lgu1nv2u0m@4ax. com>... > Need to detect when a (real 8) number changes sign. Seems the most > efficient way should be to test the bit that defines whether the > number is pos or neg? However, all the BIT funtiions (apart from > TRANSFER) seem to operate only on integers. Surely there is a way to > extract the bit that sets +/- for a real number. > > My current code is along the lines (a = real 8) > > > DO i = 2,n > if(a(i)*a(i-1) > 0.d0) CYCLE ! say 90% of cases > .... do some minor stuff (one statement) > END DO > > > That requires a real*real & i-1 operation for every case. > > I can use SIGN, but in timinig tests that worked out a lot slower than > the current code. If they were integer(8) numbers, the test I > envisage would be along the lines: > > > logical(1) no_change > integer(8), allocatable :: num(:) > integer(4) i, n Attention: kind constants are not portable !! > ALLOCATE( num( ...) ) > > no_change = BTEST (num(1), 63) > DO i = 2,n > if( BTEST (num(i), 63) == no_change) CYCLE Attention(2): comparison of Logical quantities requires .EQV. operator in stead of == !! [JvO] > no_change = .NOT.no_change > .... do some stuff > END DO > > > Anything equivalent I could use for real numbers? If you want to avoid TRANSFER you might use EQUIVALENCE integer :: a ! Simplified to single precision. real :: b equivalence (a, b) read *, b if (btest(a, 31) ) ... !! I just wonder if this is really faster than if( b < 0.0) ... !! I am rather sure that testing a(i) * a(i-1) is (much) slower than retaining pos. or neg. in a logical variable. [JvO]
Post Follow-up to this messageOn 18 Aug 2004 10:00:10 -0700, jvo_36@hotmail.com (jan van oosterwijk) wrote: > >Attention(2): comparison of Logical quantities requires .EQV. operator >in stead of == !! > > [JvO] Oops. Must be an IVF8 extension, because == works. In fact, in this case, there is about a 5% performance gain over the whole task (determining points in polygons), simply by using == rather than .EQV. in the one line of code (suggests a heavy performance hit on that one line). Still probably not a good idea if it is non-standard, but it does raise an interesting question; ie. why is .EQV. a lot slower than ==? Scarcely an inducement to be "standards compliant", especially since the code will never see the light of electrons on any VAX(!) - "in-house" code only. Anyway, as below, bit testing is not the fastest option for this application. >!! I am rather sure that testing a(i) * a(i-1) is (much) slower than >retaining pos. or neg. in a logical variable. > >[JvO] As I noted in another post in this thread, the real situation was slightly more "complex", in that "a(i)" was actually "gn(i,k)-yg". That required an extra line "gn8 = gn(i,k)-yg" before the logical test (with gn8 equivalenced to in8). In this situation, the logical bit test option turns out to be 40%-50% SLOWER than testing real*real - esp when the second real is a +/- toggle switch (only change when "gn(i,k)-yg" changes sign). Even without the extra line of code, bit testing is unlikely provide any worthwhile performance gain as the real*real seems to be costing next to no CPU time on my system. David
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.