1

I am trying to compare two numbers "a" and "b" and if a is greater than b, I would like to set another double c as 1 or else I would like to set c as 0.

The following is what I have done so far -

#include <stdio.h>
#include <math.h>

int main() {
    double a = 0.01242;
    double b = 0.04231;
    double c = ceil(fmod(a,b));
    //c should be 1 if a > b or else it should be 0
}

My problem here is it works for some numbers but usually ceil() would return something greater than 1.

I would like to do it without using any kind of operator that includes a boolean return type.

Parham Alvani
  • 2,305
  • 2
  • 14
  • 25
adty4
  • 29
  • 1
  • 1
  • 2
  • 1
    Not sure what you mean by "any kind of operator that includes a boolean return type"... is the ternary operator (`foo = bar ? 0 : 1;`) out? – Paul Roub Feb 07 '15 at 20:50
  • 2
    I don't know what you think avoiding “boolean return types” will achieve, but your currently solution, involving `fmod`, is at least as expensive as a division. – Pascal Cuoq Feb 07 '15 at 20:56
  • Does ceil have a conditional operator in its bowels – Ed Heal Feb 07 '15 at 21:45
  • Is [`signbit()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signbit.html) a conditional function? – pmg Feb 07 '15 at 22:42

3 Answers3

0

I think you can use following expression to find maximum of between a and b and use max(a, b) ^ b to find these are equal or not and then assign max(a, b) ^ b's result to c.(^ is bitwise xor)

max(a, b) = 1 / 2. * (a + b + sqrt((a - b) * (a - b)));

or

max(a, b) = 1 / 2. * (a + b + fabs(a-b));

we cannot use ^ operator on double so if you want use double following program maybe do your job :

#include <stdio.h>
#include <math.h>

double max(double a, double b)
{
    return 1 / 2. * (a + b + fabs(a-b));
}

int main(int argc, char *argv[])
{
    double b = 0.01242;
    double a = 0.04231;

    printf("%g\n", max(a, b));

    int c = ceil(max(a, b) / b);
    c = (c + 1) % c;
    /* c should be 1 if a > b or else it should be 0 */
    printf("%d\n", c);
}
Parham Alvani
  • 2,305
  • 2
  • 14
  • 25
  • your `max(a,b)` function is OK but the comparison is not you do not handle negative values at all and have no protection against division by zero. for nonzero positive values the output seems to be valid – Spektre Feb 08 '15 at 11:02
0

Interesting problem I solved it like this:

//---------------------------------------------------------------------------
double fpu_cmp(double a,double b)
    {
//  a> b -> c=1
//  a<=b -> c=0
    double c;           // a<=b     a>=b
    c=a-b;              // c<=0.0   c>0.0
    c/=fabs(c)+1e-323;  // c={-1,0} c=+1.0
    c+=fabs(c);         // c=0.0    c=+2.0
    c*=0.5;             // c=0.0    c=+1.0
    return c;
    }

//---------------------------------------------------------------------------
  • work both on positive and negative values
  • how it works is explained in rems
  • first column is what is in c if a<=b
  • second column is what is in c if a>b
  • tested on interval a,b=<-3,+3> with step 0.01 and no errors
  • if you worry about the 1e-323 constant changing the 1.0 to 0.99999999...9
  • then you can still use return ceil(c); but I think in current state it is OK already

[notes]

  • fabs can be done with single bit operation
  • c*=0.5 is just exponent decrement (bit masked)
  • so the only slow operation is the FPU division
  • the 1e-323 is just to avoid division by zero (but can significantly change result if comparing very very close numbers) this constant is the minimal value avoiding division by zero. if you are computing on numbers at least 100 times bigger then that then you should be OK
Spektre
  • 49,595
  • 11
  • 110
  • 380
0

In IEEE-754, you can compare the floating-point values as sign-magnitude integer values. So I'm using it here. The integer comparison is similar to the one I used in this answer, but unsigned version. Below is the raw version before converting to branchless

Here minus operator is not used either like the other question, but you can shorten the code by converting back to using minus.

int isGreaterI(uint64_t x, uint64_t y)
{
    if ((x ^ y) >> 63) // never happens as we only pass absolute values as below
    {
        return (x >> 63) & 1;
    }
    else
    {
        uint64_t xm   = ~x + 1ULL;
        uint64_t diff = y + xm;
        return diff >> 63;
    }
}

int isGreaterF(double a, double b)
{
    uint64_t ai = *((uint64_t*)(&a));
    uint64_t bi = *((uint64_t*)(&b));
    int result;
    if ((ai ^ bi) >> 63) // different signs
    {
        result = bi >> 63; // bi < 0, ai > 0
    }
    else
    {
        uint64_t sign = ai >> 63;
        result = isGreaterI(ai, bi);
        if (sign)
            result = !result;
    }
    return result;
}

After muxing the branches' results in the if blocks to remove conditionals and removing unneccessary branches we have the below final version

int isGreaterMagnitude(uint64_t x, uint64_t y)
{
    uint64_t xm = ~x + 1ULL;
    uint64_t diff = y + xm;
    return diff >> 63;
}

int isGreaterF(double a, double b)
{
    uint64_t ai = *((uint64_t*)(&a));
    uint64_t bi = *((uint64_t*)(&b));
    uint64_t mask = ((ai ^ bi) >> 63) + (~0ULL); // mask = 0 if a and b have different signs

    uint64_t r1 = bi >> 63;

    uint64_t sign = (int64_t)ai >> 63;
    uint64_t r2 = isGreaterMagnitude(ai, bi);
    r2 = (r2 & ~sign) | ((1 - r2) & sign);

    return (r1 & ~mask) | (r2 & mask);
}
Community
  • 1
  • 1
phuclv
  • 37,963
  • 15
  • 156
  • 475