Thread: Representing floats with color?

  1. #76
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    As I see it, it is better to waste memory than do the conversion every time.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #77
    Registered User
    Join Date
    Oct 2007
    Posts
    166
    Quote Originally Posted by Elysia View Post
    As I see it, it is better to waste memory than do the conversion every time.
    The things this code might be working with bitmaps as large as 4096X4096 pixels so that is a lot of memory, like an array size over 16 million. + the bitmap is already laid out in a good format for checking neighbors to values which will be useful.

    I will test both ways though to see what kind of speed hit the conversion produces. Might be negligable compared to other calculations I do.

  3. #78
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    You have to test what is better. I recently have made tests about these kind of things. And I have to tell you that it really depends. There is a trade-off between calculations and memory and it can even depend from system to system. We don't have the whole code to say anything more.

    Code:
    float r = (float) ((int) (val & 0x000000FF) >> 0) * div;
    Too much casting.
    val is int. div is float. The result is float. So no casting needed at all. When you have int * float the int is casted to a float. In any case you wanted this:
    Code:
    float r = (float)((float) ((val & 0x000000FF) >> 0) * div);
    or simpler
    Code:
    float r = ((val & 0x000000FF) >> 0) * div);
    An obvious optimization is:
    Code:
    float r = ((val & 0x000000FF) >> 0) / 255f);
    The f will make a division with floats.

    Also the & 0x000000FF means that you keep the last 8 bits. Thus 1 byte. So yeah, since you have a byte it makes no sense. Just emit it

  4. #79
    Registered User
    Join Date
    Oct 2007
    Posts
    166
    Quote Originally Posted by C_ntua View Post
    You have to test what is better. I recently have made tests about these kind of things. And I have to tell you that it really depends. There is a trade-off between calculations and memory and it can even depend from system to system. We don't have the whole code to say anything more.

    Code:
    float r = (float) ((int) (val & 0x000000FF) >> 0) * div;
    Too much casting.
    val is int. div is float. The result is float. So no casting needed at all. When you have int * float the int is casted to a float. In any case you wanted this:
    Code:
    float r = (float)((float) ((val & 0x000000FF) >> 0) * div);
    or simpler
    Code:
    float r = ((val & 0x000000FF) >> 0) * div);
    An obvious optimization is:
    Code:
    float r = ((val & 0x000000FF) >> 0) / 255f);
    The f will make a division with floats.

    Also the & 0x000000FF means that you keep the last 8 bits. Thus 1 byte. So yeah, since you have a byte it makes no sense. Just emit it
    Thanks, yes all the casting may not be necessary.

    I don't agree with the division optimization though. Division is a lot slower than multiplying so since division will happen often using the same value it is better to calculate it as 1.0f / 255.0f once(outside the loop) and resuse that for multiplication.

  5. #80
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    You are probably right on that.

    The other thing is try to use the float as an array rather than using bit wise operations. Like:

    Code:
    unsigned char*  ptr = (unsigned char*)&val;
    float r = val[0] * div;
    float g = val[1] * div;
    float b = val[2] * div;
    float a = val[3] * div;
    This might be faster, might be slower. I would expect it to be a little faster. Try it.

  6. #81
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Any decent compiler would transform a division-by-constant to a multiplication-by-inverse-constant anyway.
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  7. #82
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Quote Originally Posted by DrSnuggles View Post
    I don't want to store an array in memory with possibly several million floats. Working with such an array would also be slow. With a bitmap I have the benefit of being able to easially check neighbors of the values as well.
    It's still not clear why you want to do so much arithmetic on several million pixels.

    Why would working with floats be slower than working with quadruples of 4 chars? And why would checking neighbors be easier with 4 chars. If I understand your solution, you will have to look at all 4 chars for each comparison, since (for example) [255, 0, 0, 0] will be closer to [0,255,255,255] than [0,0,0,0] is to [0,0,0,10]. Correct?

    If you are starting out with float values to begin with, and are primarily trying to save space, why is EVOEx's solution not preferable? The bitmap can be an array of unions instead of an array of 4-tuples of chars. Initially you would store the float values there. Do whatever processing you need to do on them, and do only a single conversion at the end, storing the float in each pixel with the 4 chars to display the image?

    What's wrong with that?

  8. #83
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    Quote Originally Posted by DrSnuggles View Post
    Hey, I appreciate all the input. I have found a solution to this that should be fast enough to use, so it is a win situation. I save memory and can work with a single structure (the bitmap) to do all I need. It is similar to some of the latest posts. I split an integer into its bytes. Here is the code:

    Converting to color:

    Code:
    float thickness = 678460.545f;
    int val = (int) (thickness * 1000.0f); //Gives me three decimals which is enough
    float div = 1.0f / 255.0f;
    float r = (float) ((int) (val & 0x000000FF) >> 0) * div;
    float g = (float) ((int) (val & 0x0000FF00) >> 8) * div;
    float b = (float) ((int) (val & 0x00FF0000) >> 16) * div;
    float a = (float) ((int) (val & 0xFF000000) >> 24) * div;
    Converting back to float:

    Code:
    byte b1 = (byte) ((int)(r * 255.0f));
    byte b2 = (byte) ((int)(g * 255.0f));
    byte b3 = (byte) ((int)(b * 255.0f));
    byte b4 = (byte) ((int)(a * 255.0f));
    int vv = 0;
    vv += (int) ((b1 & 0x000000FF) << 0);
    vv += (int) ((b2 & 0x000000FF) << 8);
    vv += (int) ((b3 & 0x000000FF) << 16);
    vv += (int) ((b4 & 0x000000FF) << 24);
    float thickness2 = vv * 0.001f;
    If you see any optimization that can be done let me know. As an example removing the "& 0x000000FF" in the converting back makes it still work. Not sure if that is safe though...?

    Also the talk about thickness is not really relevant here, that is a separate calculation I do on a 3d object that is already covered. Only in the final step will the bitmap display something worth looking at.

    Will check out your solution as well iMalc, thanks.
    the one i posted here on page 3 is probably faster

    http://cboard.cprogramming.com/showp...6&postcount=39

  9. #84
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    this still seems like madness though. why can't you just cast it??

  10. #85
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Magos View Post
    Any decent compiler would transform a division-by-constant to a multiplication-by-inverse-constant anyway.
    Indeed, and in fact I was relying on this for the code I provided. Interestingly enough though, whether VS2005 and up do this sometimes depends on the floating point consistency model selected for the project. I mean for powers of two it'll surely convert to a multiplication, but for something like dividing by 3 it probably wont use a multiplication by 1/3rd for the precise model, because that can't be represented exactly, whereas 3 can, and the multiplication result might differ by a couple of least-significant bits in the significand.

    Quote Originally Posted by DrSnuggles View Post
    Thanks, yes all the casting may not be necessary.

    I don't agree with the division optimization though. Division is a lot slower than multiplying so since division will happen often using the same value it is better to calculate it as 1.0f / 255.0f once(outside the loop) and resuse that for multiplication.
    Yes division is certainly a lot slower than even 3 multiplications. Any reduction in the number of divisions performed has got to be a win. There's no harm in explicitly doing the optimisation of reducing the divides by hand here.

    Note that with the method I posted, you don't need any premultiplication step. It should be able to operate on whatever range of values your float initially contains, and maintains accuracy for small and large values. By all means use whatever turns out to be fastest though

    Minor optimisation, always do the bitmasks after a right shift:
    Code:
    float thickness = 678460.545f;
    unsigned int val = (unsigned int) (thickness * 1000.0f); //Gives me three decimals which is enough
    float div = 1.0f / 255.0f;
    float r = (val & 0xFF) * div;
    float g = ((val >> 8) & 0xFF) * div;
    float b = ((val >> 16) & 0xFF) * div;
    float a = ((val >> 24) * div;
    It takes less bytes of machine code to represent smaller integer constants. And leaving out the last bitmask is safe so long as val is positive, hence I've made it unsigned to be sure. I'd also leave out the zero-shift even though it doesn't look as pretty and the compiler would have generated the same code anyway, but that's just me.
    Last edited by iMalc; 12-21-2008 at 01:03 PM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  11. #86
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    couldn't you also bitshift by 8 instead of dividing by 256?

  12. #87
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Quote Originally Posted by m37h0d View Post
    couldn't you also bitshift by 8 instead of dividing by 256?
    And you think the compiler makers didn't think of this, why?
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  13. #88
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    because they've made it floating point multiplication? i guess the real answer is that they can't do that because that would shift all the data off the end of the end, and so they'd get nothing.

    this whole thing seems odd to me tho. seems like a lot of trouble to somewhat optimize an inherently inefficient system.
    Last edited by m37h0d; 12-21-2008 at 01:41 PM.

  14. #89
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    byte b1 = (byte) ((int)(r * 255.0f));
    byte b2 = (byte) ((int)(g * 255.0f));
    byte b3 = (byte) ((int)(b * 255.0f));
    byte b4 = (byte) ((int)(a * 255.0f));
    int vv = 0;
    vv += (int) ((b1 & 0x000000FF) << 0);
    vv += (int) ((b2 & 0x000000FF) << 8);
    vv += (int) ((b3 & 0x000000FF) << 16);
    vv += (int) ((b4 & 0x000000FF) << 24);
    float thickness2 = vv * 0.001f;
    You have effectively removed over 2 million colors by selecting int for vv. Colors are unsigned int which gives you the full range of over 4 million colors in 32-bit color. Negative r,g,b values do not make sense and will most likely result in some color inversion. Your version will overflow the data type you have selected.

  15. #90
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    Wow. Long thread.

    As it seems to have been repeated quite a lot, it's memory overhead of using two arrays vs. processing overhead of casting (even if it's some custom cast). Well? If you've chosen to let the CPU take the heat, then there are many solutions here (i.e. last six pages). However, I suggest you use two arrays. What's a factor of two among programmers?
    Last edited by CodeMonkey; 12-22-2008 at 12:46 AM. Reason: grammar
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Critique my lighting model.
    By psychopath in forum Game Programming
    Replies: 4
    Last Post: 08-12-2006, 06:23 PM
  2. egavga.bgi problem
    By sunil21 in forum A Brief History of Cprogramming.com
    Replies: 3
    Last Post: 09-22-2003, 05:06 PM
  3. My opinion on skin color
    By Leeman_s in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 07-11-2003, 12:12 PM
  4. [WinAPI] Developing a color customizable program
    By Templario in forum Windows Programming
    Replies: 6
    Last Post: 02-04-2003, 06:12 PM
  5. Just one Question?
    By Irish-Slasher in forum C++ Programming
    Replies: 6
    Last Post: 02-12-2002, 10:19 AM