sign_command (e.g not_negative) missing(?) in C++ (/C)

T

tmartsum

I am not an expert on C++(/C), but also not a complete beginner.

I was writing a faster cos (and sin) approximation based on
precalculated data (with some success) when I discovered that going
from double to int is quite expensive, so maybe a cos/sin approximation
without precalculation would be better (faster).

Nevertheless I (still) needed to find out where on the unit-cirkle the
angle
(a double (v) from 0 to 2PI) was. And I looked for a command like

int not_negative(double d) // return 1 if d==(+)0.0, d==1.2 aso else 0
(and int not_positive(double d) // return 1 if d==-0.0 d==-1.6 (else
0))

My guess is that such a command could be made real fast (with some
bit-mangleling - am I wrong here?) I do not know how dobbles looks in
bits
and if it is the same on all machines, but I think it could be made
fast ....

If I had a fast command like this (and gcc/g++ with -O3 does not make
the
comparison x>=0 fast - maybe the answer is that that is the real
problem
,but if it is possible to make a fast function without a compare the
language would signal that this works without a compare and therefore
is faster)

it would be possible to write something like :
Depending on how fast the function is this might he faster than a
binary
search on v.

Does anybody has some comments on this ?

double cos(double v)
{
:rerun
v=fabs(v)-(2.0*PI);
int part = 0;

part=part + not_negative(v); // v was bigger than 2PI
v=v+PI/4.0;
part=part + not_negative(v);
v=v+PI/4.0;
part=part + not_negative(v);
v=v+PI/4.0;
part=part + not_negative(v);
v=v+PI/4.0;
part=part + not_negative(v);
v=v+PI/4.0;
part=part + not_negative(v);
v=v+PI/4.0;
part=part + not_negative(v);
v=v+PI/4.0;
part=part + not_negative(v);

switch (part)
{
case 0 : return something for case0;
case 1 : return something for case1;
case 2 : return something for case2;
case 3 : return something for case3;
case 4 : return something for case4;
case 5 : return something for case5;
case 6 : return something for case6;
case 7 : return something for case7;
case 8 : x is not in [0;2PI].
// This was not a "part" of the deal but
// fix x and goto rerun
}
}
 
Z

Zara

tmartsum said:
I am not an expert on C++(/C), but also not a complete beginner.

I was writing a faster cos (and sin) approximation based on
precalculated data (with some success) when I discovered that going
from double to int is quite expensive, so maybe a cos/sin approximation
without precalculation would be better (faster).

Nevertheless I (still) needed to find out where on the unit-cirkle the
angle
(a double (v) from 0 to 2PI) was. And I looked for a command like

int not_negative(double d) // return 1 if d==(+)0.0, d==1.2 aso else 0
(and int not_positive(double d) // return 1 if d==-0.0 d==-1.6 (else
0))

My guess is that such a command could be made real fast (with some
bit-mangleling - am I wrong here?) I do not know how dobbles looks in
bits
and if it is the same on all machines, but I think it could be made
fast ....
The solution would not be portable. But, anyhow, take a look at your
compiler implementation details about the double format, which will be
formed by exponent and mantissa, locate the sign bit in the mantissa,
make a non-portable implementation dependent be-careful-with-it method
to test it.
An be ready to change it as soon as you discover better ways (such as
division to discover how many times PI/4.0 is contained in a double)

Zara
 
T

tmartsum

Zara skrev:

The solution would not be portable. But, anyhow, take a look at your
compiler implementation details about the double format, which will be
formed by exponent and mantissa, locate the sign bit in the mantissa,
make a non-portable implementation dependent be-careful-with-it method
to test it.
An be ready to change it as soon as you discover better ways (such as
division to discover how many times PI/4.0 is contained in a double)

Thanks for the answer - It was my guess that it would not be portable.
(And I want to write portable C++ (or in this case it is just C)

My subject was also : "sign_command missing(?) in C++" hence the
compiler would probably know how to do this quick for a given platform,
but I can make no fast algoritm unless I write C++ that creates C++
(Which I am not fond of.)

PS : Something I should have written first :
int part = static_cast<int> (floor(v*(1/(2.0*PI)*8)));

is not (as I remember it) performing good. Both the cast and floor are
expensive. I was considering not using pre_calculated data of 2
reasons.
1) The lookup with a possible cache-miss
2) The cast from double to int
 
Z

Zara

tmartsum said:
My subject was also : "sign_command missing(?) in C++" hence the
compiler would probably know how to do this quick for a given platform,
but I can make no fast algoritm unless I write C++ that creates C++
(Which I am not fond of.)

The sign command should be

inline bool not_negative(double d) {return d>=0.0;}

This is the most efficient way, if we honour portability.
PS : Something I should have written first :
int part = static_cast<int> (floor(v*(1/(2.0*PI)*8)));

is not (as I remember it) performing good.

This one is sub-optimal, it is in fact redundant. *IF* you guarantee
that v >=0.0, then the following expression is enough:

int part = static_cast<int> (v*(1/(2.0*PI)*8));

Because casting form real types to integer types is done rounding
towards zero.
 
M

msalters

tmartsum schreef:
My guess is that a [sign] command could be made real fast (with some
bit-mangleling - am I wrong here?) I do not know how dobbles looks in
bits and if it is the same on all machines, but I think it could be
made fast ....

If I had a fast command like this (and gcc/g++ with -O3 does not make
the comparison x>=0 fast - maybe the answer is that that is the real
problem

It is. The check d>=0.0 should be optimized by a peephole optimizer.
This is a common form of optimizing: take a fixed instruction sequence
from the unoptimized code and replace it by a better form.

HTH,
Michiel Salters
 
M

Martin Eisenberg

tmartsum said:
int part = static_cast<int> (floor(v*(1/(2.0*PI)*8)));

is not (as I remember it) performing good. Both the cast and
floor are expensive.

If you're on x86, you can try the FISTTP truncating integer store
instruction to avoid the gymnastics a compiler is forced into
generating from the cast because it cannot rely on the FPU being set
to any particular rounding mode. That would mean a line of inline
assembly which is nonportable across compilers in addition to across
platforms. Intel's instruction set reference is at
http://www.intel.com/design/pentium4/manuals/253666.htm .

As a side note, you may want to evaluate floating-point constant
expressions yourself as a compiler is not allowed to do that.


Martin
 
T

tmartsum

inline bool not_negative(double d) {return d>=0.0;}

Yes - but compiler (g++ -O3) does not make it fast enough.
I will look into it - but it uses a

fucomp
and
fnstsw

which are not high performing.
I will find out what to write and then mail it to them.

(And I use the cast just for the example - to show the cast and get rid
of a warning - warnings are half errors)

As I mention later a actually use lrint ....
 
T

tmartsum

Hello Mr. Michiel Salters

Thanks for your answer. I will not try to figure out some smart
assembly code and mail it to gcc (if I can create anything usefull).

What I was considering was if it was more idiomatic to have
such a function it in math.h. There would be at least two good reasons.

1) Avoid thinking thinking about nan (like fabs does).
(*This might be a reason for the compiler to do the compare.
If v was nan it must return false*)

2) Force compile-writes to think about this special case and make them
optimize the function bitwise.

Timing on my cpu indicates that this switch would indead be faster that
a binary search for 8 cases if this function was lightning fast.

So I was thinking if I could have overlooked it. But I will make a
peephole-paterne unless I stumble upon anther solution. Thanks.

Thorbjørn Martsum
 
T

tmartsum

Hi Martin Eisenberg

Acually I use lrint. It expands to FISTTP. =)
Quite fast - and a lot faster than the cast - but not fast fast....

regards
Thorbjørn
 
B

Ben

tmartsum said:
inline bool not_negative(double d) {return d>=0.0;}

Yes - but compiler (g++ -O3) does not make it fast enough.
I will look into it - but it uses a

fucomp
and
fnstsw

which are not high performing.
I will find out what to write and then mail it to them.

(And I use the cast just for the example - to show the cast and get rid
of a warning - warnings are half errors)

....the cast does not solve the "half-error", it merely makes the warning
go away.

Ben
 
T

tmartsum

The cast implies that "I think I know what I am doing" on a critical
spot.
I hate working in projects where warnings are accepted.

I do not consider the assignment as an error, but wheather it is or not
is a matter of view and philosophy and far away from the problem I with


NO FAST WAY TO GET THE SIGNBIT IN C/C++

(unless you cheat and asumes that double and float follwos IEEE 754)
 
T

tmartsum

The function I was searching for was signbit in math.h
(Are there any (real) experts reading this forum?)

I found out reporting an error to g++ in the following code:
int is_not_positive(double v)
{
return ((reinterpret_cast<unsigned int*>(&v)[1]) >> 31);
}

There is no union so there is "c++" standard does not guarantee it will
work however there is no reason it should not work on x86.
(A union should be used and it is just as fast - the compiler can
optimize it)
But beside saying that it was both fixed in newer version and the code
was bad (which I knew) they informed about signbit.
 
P

P.J. Plauger

The function I was searching for was signbit in math.h
(Are there any (real) experts reading this forum?)

Yes, I knew about it. But:

a) it's a C99 function, soon to appear in TR1 but not
officially available to C++

b) you've been so preoccupied with performance in the small
that I didn't feel like defending whether the function can
be done in one instruction or three.
I found out reporting an error to g++ in the following code:
int is_not_positive(double v)
{
return ((reinterpret_cast<unsigned int*>(&v)[1]) >> 31);
}

Why shift right when all you need is zero/nonzero?
There is no union so there is "c++" standard does not guarantee it will
work however there is no reason it should not work on x86.

Except that the byte order is wrong.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
T

tmartsum

it's a C99 function, soon to appear in TR1 but not officially available to C++

a) Ok maybe I was a bit rude - and maybe you are right that it is not
C++ however the gcc people told me to use it. (Normally all C is also
C++ or will be it later =) )
you've been so preoccupied with performance in the small that I didn't feel like defending whether the function can be done in one instruction or three.

b) OK - I may have been a little to interessetet in speed and maybe not
been that friendly to all replys. (When persons has talked about a
completly different than the problem or not understood a bit of it)
Why shift right when all you need is zero/nonzero?

c) Actually I need the zero/one. I want to do some calculations on a
double and meanwhile sometimes call sign and add it to a variabel (not
excatly the way done in my first post - but similar). Then later I will
switch the sum of serveral signs.

Getting a zero/one version from the nonzero/zero version is not hard.
(!! in front could be considered) but another option is :

const int signbit_shift = round(log2(signbit(-1.0)))
inline /* maybe a macro is better */ is_not_positive(double v)
{
if (signbit(-1.0) == 1) // compilers should be able to eliminate the
if
return signbit(v);
extern const int signbit_shift;
return signbit(v) << signbit_shift
}
Except that the byte order is wrong.
?? not understood - it worked on my machine ... But many things are
wrong with it - intsize must also be 32 doublesize=64 .... (could
maybe be fixed with macros) - but then there is the fact that
optimizeres can be tricked by it. (And if doubles are not IEEE 754
standard that is also wrong)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top