Thread: custom min/max function

  1. #1
    Registered User cph's Avatar
    Join Date
    Sep 2008
    Location
    Indonesia
    Posts
    86

    custom min/max function

    I probably saw this somewhere, but can't remember where and when.
    Code:
    inline int fmax(int a, int b)
    {
        const int result[2] = { a, b };
    
        return result[result[0] < result[1]];
    }
    
    inline int fmin(int a, int b)
    {
        const int result[2] = { a, b };
    
        return result[result[0] > result[1]];
    }
    My question is: is it *really* safe?
    Do not stare at my avatar.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,666
    Relational operators return a bool type.

    The C++ standard states this.
    An rvalue of type bool can be converted to an rvalue of type int, with false becoming zero and true becoming one.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User cph's Avatar
    Join Date
    Sep 2008
    Location
    Indonesia
    Posts
    86
    Quote Originally Posted by Salem View Post
    Relational operators return a bool type.

    The C++ standard states this.
    An rvalue of type bool can be converted to an rvalue of type int, with false becoming zero and true becoming one.
    do I have to do this:
    Code:
    inline int fmax(int a, int b)
    {
        const int result[2] = { a, b };
    
        return result[static_cast<unsigned int>(result[0] < result[1])];
    }
    to make sure it's safe?
    Do not stare at my avatar.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,666
    No, that doesn't make it any more safe than it already is. If by some bizarre accident the bool promotion gave you something other than 0 or 1, then it would be out of range whether it was signed or unsigned.

    You're not buying into some "branches are evil" (qu)hackery are you?

    Code:
    int fmin2(int a, int b) {
      return a < b ? a : b;
    }
    The optimised assembler for this is only 4 instructions, and none of them are branches.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User cph's Avatar
    Join Date
    Sep 2008
    Location
    Indonesia
    Posts
    86
    Quote Originally Posted by Salem View Post
    ...
    You're not buying into some "branches are evil" (qu)hackery are you?
    ...
    guilty as charged.
    Do not stare at my avatar.

  6. #6
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by cph View Post
    guilty as charged.
    LOL (I'm not laughing at you, but you have to admit that's a pretty novel implementation of min/max)

    Although your reasoning is somewhat dubious, I cannot fault you for trying different methods. It's cool that you've done this as an exercise. The technique you've "come up with" is useful so it's not as though you've wasted your time, and you've learned something so you've used your time doubly well. Even better, by asking a sensible question you've learnt even more! I give you a Hodor Cookie as a reward.

    Now, to see which is more efficient (not that it matters, but you may as well keep experimenting and thinking since you're on a roll) you can go two ways: a) you can look at the assembly generated and do some calculations; or b) you can take a more empirical approach and implement two test programs, perform min or max a million times or so for each program and time how long things take (e.g. time ./mymin and time ./mymin2). If you try option (b) be careful your compiler doesn't just optimise the loop (if you use a loop) away because you're not using intermediate results or something

  7. #7
    Registered User cph's Avatar
    Join Date
    Sep 2008
    Location
    Indonesia
    Posts
    86
    Quote Originally Posted by Hodor View Post
    LOL (I'm not laughing at you, but you have to admit that's a pretty novel implementation of min/max)

    Although your reasoning is somewhat dubious, I cannot fault you for trying different methods. It's cool that you've done this as an exercise. The technique you've "come up with" is useful so it's not as though you've wasted your time, and you've learned something so you've used your time doubly well. Even better, by asking a sensible question you've learnt even more! I give you a Hodor Cookie as a reward.

    Now, to see which is more efficient (not that it matters, but you may as well keep experimenting and thinking since you're on a roll) you can go two ways: a) you can look at the assembly generated and do some calculations; or b) you can take a more empirical approach and implement two test programs, perform min or max a million times or so for each program and time how long things take (e.g. time ./mymin and time ./mymin2). If you try option (b) be careful your compiler doesn't just optimise the loop (if you use a loop) away because you're not using intermediate results or something
    hooray...!

    well, it also works with double.
    Code:
    inline double fmax(double a, double b)
    {
        const double result[2] = { a, b };
    
        return result[static_cast<unsigned int>(result[0] < result[1])];
    }
    
    inline double fmin(double a, double b)
    {
        const double result[2] = { a, b };
    
        return result[static_cast<unsigned int>(result[0] > result[1])];
    }
    Last edited by cph; 11-12-2015 at 01:23 AM.
    Do not stare at my avatar.

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by cph
    hooray...!
    I think you meant "hodoray"
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Yes, well of course it works and there is technically wrong with it (as far as compliance with the C standard etc go), but you really wouldn't do this beyond it being an academic exercise (the compiler is going to optimise the code to something faster than what you've done and you may even get in its way by confusing the poor thing).

    I gave you the cookie because I love to see people experimenting and coming up with "out of the box solutions". Please keep experimenting.

    The method you're using, although not useful for this case beyond the value it gives to you of achievement, learning, etc, is actually useful (and quite acceptable IMO) in some situations (just not for this because in the compiler non-optimised state you don't really know if your method (avoiding branching) is faster and even if it is using your compiler and CPU/architecture it would not necessarily true for all CPUs or architectures. You lose readability for no gain in the end. But, as I said, experimentation is, of course, cool.

    A possibly accepted use of the "method" (I accept it, others may not)

    Using branches (although what an optimising compiler does makes that statement relatively pointless)
    Code:
    const char *to_bool_string(int val)
    {
        return !!val ? "true" : "false";
    }
    Not using branches
    Code:
    const char *to_bool_string(int val)
    {
        static const char *s[] = { "false", "true" };
        return s[!!val];
    }
    Maybe this isn't the best example now that I think about it, but it serves as a demonstration of where I think your "method" might be more pragmatic. I'll leave it to you to work out why I've got !!val
    Last edited by Hodor; 11-12-2015 at 02:24 AM. Reason: fixed messed up thingy

  10. #10
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Turning a bool to a string does not have to involve arrays at all, in fact std::boolalpha will do it in the middle of a stream.

    I would like to note that the one place I have seen this construction is in python where for the longest time there was no conditional operator - they used this trick to emulate ones behavior. It seems odd to me that since we have such an operator we'd go to such extremes not to use it.
    Last edited by whiteflags; 11-12-2015 at 03:51 AM.

  11. #11
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Yeah, well, I personally believe this topic belongs in C and not C++. Of course you'd use std::boolalpha in C++ (which is one of the reasons a changed my mind and said "maybe this isn't the best example now that I think about it")

    Edit: I don't think it's a "trick" at all.

    Edit 2: And if you read what I wrote I kind of mentioned that going to such extremes to not use the "conditional operator" (which is essentially equivalent to "I don't wanna use branches") is, most of the time, not worth it (the compiler will optimise such things if it can anyway; leaving such low-level optimisations to the compiler means that performance might be improved across different platforms by just leaving things the way they are and not trying to do better than what the compiler might do). Well, it is worth it if you're learning and experimenting etc. I hate it when people say "don't do that! There is [this] that already does that!" That does not encourage learning at all, in any way whatsoever. It's worth pointing out that "nobody would do this is a real life situation", of course. But that's totally different to discouraging people from thinking outside of the box and experimenting.

    Edit 3: I am not giving you a cookie
    Last edited by Hodor; 11-12-2015 at 06:10 AM.

  12. #12
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I really like how you made this all about you and what you think.

    Yeah, well, I personally believe this topic belongs in C and not C++.
    It isn't though.

    Edit 3: I am not giving you a cookie
    I'm not sure what you mean, but if you don't want me to post in thread's in which you've posted, message received. I'd rather you not do anything to me rather than have you do something and think that means I owe you a favor. Dick.
    Last edited by whiteflags; 11-13-2015 at 07:02 AM.

  13. #13
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by whiteflags View Post
    I'm not sure what you mean, but if you don't want me to post in thread's in which you've posted, message received. I'd rather you not do anything to me rather than have you do something and think that means I owe you a favor. Dick.
    I'm not sure where you got that idea ("but if you don't want me to post in thread's in which you've posted"). Why would I not want you to post in threads in which I've posted? That's crazy.

    I don't expect any favours.

    If you really want a cookie I'll bake you one, though. Here, have it.

    P.S. My name is Hodor, not Richard.

    Edit: I really have no idea why you think I dislike you or have some kind of grudge, or something. I assure you that that's not the case. *confused*

    This animosity you have towards me seems to be related to a PM a sent you regarding an answer you posted here. I am happy for that conversation to be made public. The only reason I sent it via PM was because I thought that, perhaps, you just weren't thinking clearly that day (because all your other posts and post history seemed to indicate that you are very knowledgeable). I sent it via PM because I thought you'd made a simple mistake and it was not worth posting publicly. In hindsight I should have just mentioned it in the thread. (Edit: because I'm a nice guy and didn't want to contradict what seemed like an innocent lapse in public. That is the last time I will take that approach, for sure).
    Last edited by Hodor; 11-13-2015 at 07:35 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. A custom gets function
    By aijazbaig1 in forum C Programming
    Replies: 17
    Last Post: 02-02-2008, 05:21 PM
  2. Defining a custom function
    By Nalif in forum C Programming
    Replies: 3
    Last Post: 10-01-2006, 12:40 PM
  3. Custom Message Function
    By GaPe in forum C++ Programming
    Replies: 4
    Last Post: 04-19-2004, 12:07 AM
  4. Custom String Parsing Function
    By Unregistered in forum C++ Programming
    Replies: 2
    Last Post: 05-01-2002, 11:07 PM
  5. need suggestion for custom randomize function
    By Unregistered in forum C++ Programming
    Replies: 1
    Last Post: 03-22-2002, 04:59 AM

Tags for this Thread