CodingRounding numbers

 

Press Ctrl+Enter to quickly submit your post
Quick Reply  
 
 
  
 From:  Mikee  
 To:  ALL
39627.1 
I've decided to strip apart, refactor, optimise and unit test my little colour library (http://code.google.com/p/colorjizz/)

I've been fixing a few bugs that have come out from the unit testing, and while doing it I've been wondering about the way I'm rounding numbers.

using the following:

code:
 
(0.5 + number) | 0
 


Seems a hell of a lot faster than using the native rounding method in each language. In fact, in PHP it's running 4 times faster when using this other method.

I'm guessing that I'm safe to use this because all my unit tests so far are passing fine. Does anyone know of a reason I should stick to the native round() methods? Can anyone explain to me (in simple terms) why round() methods are so much slower?

http://jsfiddle.net/APcME/1/
0/0
 Reply   Quote More 

 From:  Matt  
 To:  Mikee     
39627.2 In reply to 39627.1 
Are you're only interested in rounding to 1 decimal place?

The benefit to the native (PHP) round function is the optional number of digits it allows you to round to and the different types of rounding, i.e. round half-up, half-down, etc.

Testing for all those options is what probably accounts for the speed difference.

doohicky

0/0
 Reply   Quote More 

 From:  af (CAER)  
 To:  Mikee     
39627.3 In reply to 39627.1 
I use that rounding method in my noise texture generator.

I think the reason it's faster is it can be optimised better - it's an arithmetic operation rather than a function call.

From what I remember the main downside is that it doesn't work properly (by which I mean in a mathematically correct way) on negative numbers.
0/0
 Reply   Quote More 

 From:  Mikee  
 To:  Matt     
39627.4 In reply to 39627.2 
Ok thanks Matt.

I've just been reading that really you shouldn't have more than 1 assertion per test case. Whoops.......

php code:
 
<?php
 
require_once 'colorjizz.php';
 
class CMYTest extends PHPUnit_Framework_TestCase
{
    const DELTA = 0.002;
 
 
    public function testToHexAndBack()
    {
      for ($c=0; $c<=1; $c+=0.05)
      {
        for ($m=0; $m<=1; $m+=0.05)
        {
          for ($y=0; $y<=1; $y+=0.05)
          {
            $cmy = CMY::create($c, $m, $y)->toHex()->toCMY();
            $this->assertEquals($c, $cmy->c, null, self::DELTA);
            $this->assertEquals($m, $cmy->m, null, self::DELTA);
            $this->assertEquals($y, $cmy->y, null, self::DELTA);
          }
        }
      }
    }
 
    public function testToRGBAndBack()
    {
      for ($c=0; $c<=1; $c+=0.05)
      {
        for ($m=0; $m<=1; $m+=0.05)
        {
          for ($y=0; $y<=1; $y+=0.05)
          {
            $cmy = CMY::create($c, $m, $y)->toRGB()->toCMY();
            $this->assertEquals($c, $cmy->c, null, self::DELTA);
            $this->assertEquals($m, $cmy->m, null, self::DELTA);
            $this->assertEquals($y, $cmy->y, null, self::DELTA);
          }
        }
      }
    }
 
    public function testToXYZAndBack()
    {
      for ($c=0; $c<=1; $c+=0.05)
      {
        for ($m=0; $m<=1; $m+=0.05)
        {
          for ($y=0; $y<=1; $y+=0.05)
          {
            $cmy = CMY::create($c, $m, $y)->toXYZ()->toCMY();
            $this->assertEquals($c, $cmy->c, null, self::DELTA);
            $this->assertEquals($m, $cmy->m, null, self::DELTA);
            $this->assertEquals($y, $cmy->y, null, self::DELTA);
          }
        }
      }
    }
 
 
    public function testToCMYKAndBack()
    {
      for ($c=0; $c<=1; $c+=0.05)
      {
        for ($m=0; $m<=1; $m+=0.05)
        {
          for ($y=0; $y<=1; $y+=0.05)
          {
            $cmy = CMY::create($c, $m, $y)->toCMYK()->toCMY();
            $this->assertEquals($c, $cmy->c, null, self::DELTA);
            $this->assertEquals($m, $cmy->m, null, self::DELTA);
            $this->assertEquals($y, $cmy->y, null, self::DELTA);
          }
        }
      }
    }
 
    public function testToYxyAndBack()
    {
      for ($c=0; $c<=1; $c+=0.05)
      {
        for ($m=0; $m<=1; $m+=0.05)
        {
          for ($y=0; $y<=1; $y+=0.05)
          {
            $cmy = CMY::create($c, $m, $y)->toYxy()->toCMY();
            $this->assertEquals($c, $cmy->c, null, self::DELTA);
            $this->assertEquals($m, $cmy->m, null, self::DELTA);
            $this->assertEquals($y, $cmy->y, null, self::DELTA);
          }
        }
      }
    }
 
    public function testToCIELabAndBack()
    {
      for ($c=0; $c<=1; $c+=0.05)
      {
        for ($m=0; $m<=1; $m+=0.05)
        {
          for ($y=0; $y<=1; $y+=0.05)
          {
            $cmy = CMY::create($c, $m, $y)->toCIELab()->toCMY();
            $this->assertEquals($c, $cmy->c, null, self::DELTA);
            $this->assertEquals($m, $cmy->m, null, self::DELTA);
            $this->assertEquals($y, $cmy->y, null, self::DELTA);
          }
        }
      }
    }
 
    public function testToCIELChAndBack()
    {
      for ($c=0; $c<=1; $c+=0.05)
      {
        for ($m=0; $m<=1; $m+=0.05)
        {
          for ($y=0; $y<=1; $y+=0.05)
          {
            $cmy = CMY::create($c, $m, $y)->toCIELCh()->toCMY();
            $this->assertEquals($c, $cmy->c, null, self::DELTA);
            $this->assertEquals($m, $cmy->m, null, self::DELTA);
            $this->assertEquals($y, $cmy->y, null, self::DELTA);
          }
        }
      }
    }
 
    public function testToHSVAndBack()
    {
      for ($c=0; $c<=1; $c+=0.05)
      {
        for ($m=0; $m<=1; $m+=0.05)
        {
          for ($y=0; $y<=1; $y+=0.05)
          {
            $cmy = CMY::create($c, $m, $y)->toHSV()->toCMY();
            $this->assertEquals($c, $cmy->c, null, self::DELTA);
            $this->assertEquals($m, $cmy->m, null, self::DELTA);
            $this->assertEquals($y, $cmy->y, null, self::DELTA);
          }
        }
      }
    }
}
 
?>
 
0/0
 Reply   Quote More 

 From:  Peter (BOUGHTONP)  
 To:  Mikee     
39627.5 In reply to 39627.4 
quote:
I've just been reading that really you shouldn't have more than 1 assertion per test case.

If anyone says explicitly that then they're probably an idiot.

Each test case should* be a test case, but use however many assertions it takes to test that case.

*It's partly just a benefit of maintainability/comprehension (so personal preference), but also a matter of not having logic in your test cases which could itself contain bugs (that then potentially obscures actual bugs).


If the code you posted was mine, I'd probably simplify the existing functions to this:
php code:
public function testToHexAndBack()
{
	$cmy = CMY::create($c, $m, $y)->toHex()->toCMY();
	$this->assertEquals($c, $cmy->c, null, self::DELTA);
	$this->assertEquals($m, $cmy->m, null, self::DELTA);
	$this->assertEquals($y, $cmy->y, null, self::DELTA);
}


And then process them like this:
php code:
function testRoundingStuff()
{
	for ($c=0; $c<=1; $c+=0.05)
	{
		for ($m=0; $m<=1; $m+=0.05)
		{
			for ($y=0; $y<=1; $y+=0.05)
			{
				testToHexAndBack($c,$m,$y);
				testToRGBAndBack($c,$m,$y);
				// etc
			}
		}
	}
}
0/0
 Reply   Quote More 

 From:  Mikee  
 To:  Peter (BOUGHTONP)     
39627.6 In reply to 39627.5 
The problem with that (I think) is that if a single assertion fails in that test, it wont run the rest.
0/0
 Reply   Quote More 

 From:  Mikee  
 To:  ALL
39627.7 

CMYK is a bugger to unit test.

 

$cmyk = new CMYK(0.05, 0.05, 0.05, 0);
$rgb = $cmyk->toRGB()

 

rgb gives: 242, 242, 242

 

$rgb->toCMYK() gives 0, 0, 0, 0.05

 

Pretty much every other implementation of this online seems to do the same, although with photoshop:

 

CMYK (%): 5, 5, 5, 0

 

gives:

 

RGB: 239, 236, 234

 

and CMYK (%): 0, 0, 0, 5

 

gives RGB: 241, 242, 242

 

Grr.

 

 

0/0
 Reply   Quote More 

 From:  Peter (BOUGHTONP)  
 To:  Mikee     
39627.8 In reply to 39627.6 
Get better testing software, that lets you specify to keep going.
0/0
 Reply   Quote More 

 From:  af (CAER)  
 To:  Mikee     
39627.9 In reply to 39627.7 
Be careful when using photoshop that you're not complicating things with colour profiles. That's a whole other headache.
0/0
 Reply   Quote More 

 From:  Mikee  
 To:  af (CAER)     
39627.10 In reply to 39627.9 

I really shouldn't have got involved in colours considering I hate them.

 

Might make it so that everything is forced to go through a greyscale function before it's outputted.

0/0
 Reply   Quote More 

 From:  af (CAER)  
 To:  Mikee     
39627.11 In reply to 39627.10 
You could investigate L*a*b too; from what I remember, that's what Photoshop uses internally to convert between colour types/spaces.
0/0
 Reply   Quote More 

 From:  koswix  
 To:  Mikee     
39627.12 In reply to 39627.10 
Your PB and I claim my 5 brick.



                                                
                                                
                                                
                           ▪                    
             ┌────┐    ┌────┐                      
          │    │    │    │ ▪                    
          │    └────┘    │                      
          │   ──┐  ┌──   │ ▪                    
   ┌──────┤    ▪    ▪    │                      
  ┌┘      │              │ ▪                    
┌─┤       └──┐  │  │  ┌──┘                      
│ │          │ ││  ││ │   ┌─┐                   
│ │          └─┼┤  └┴─┴───┘ │                   
│ │           ─┘│           │                   
│ │   ┌──────┐  └┬──────────┘                   
  │   │      │   │                              
  │   │      │   │                              
  └───┘      └───┘                              
0/0
 Reply   Quote More 

 From:  Dan (HERMAND)  
 To:  koswix     
39627.13 In reply to 39627.12 

What about his PB?

 

(Welcome to '99)

0/0
 Reply   Quote More 

 From:  koswix  
 To:  Dan (HERMAND)     
39627.14 In reply to 39627.13 

\o/

 


I read a summary thing that one of my lecturers wrote about my assessments in a CAD class at college. He had written "you're drawings have continued to improve". He also continually goes on about what he's going to learn us, telling us that we've already drew something so it'll be easy. Amongst other cringe inducing phrases. A fucking /lecturer/. (fail)




                                                
                                                
                                                
                           ▪                    
             ┌────┐    ┌────┐                      
          │    │    │    │ ▪                    
          │    └────┘    │                      
          │   ──┐  ┌──   │ ▪                    
   ┌──────┤    ▪    ▪    │                      
  ┌┘      │              │ ▪                    
┌─┤       └──┐  │  │  ┌──┘                      
│ │          │ ││  ││ │   ┌─┐                   
│ │          └─┼┤  └┴─┴───┘ │                   
│ │           ─┘│           │                   
│ │   ┌──────┐  └┬──────────┘                   
  │   │      │   │                              
  │   │      │   │                              
  └───┘      └───┘                              
0/0
 Reply   Quote More 

 From:  Mikee  
 To:  af (CAER)     
39627.15 In reply to 39627.11 
My library can convert to/from Lab..

for example:

php code:
 
use MischiefCollective\ColorJizz\Formats\Hex;
 
// im not sure why you'd ever want to do this
echo Hex::fromString('CC0000')->toCIELab()->toHSV()->toRGB()->toHex()->toString(); // CC0000
 
// or..
use MischiefCollective\ColorJizz\Formats\CIELab;
echo CIELab::create(53, 80, 69)->toHex()->toString(); // FE0000
 


But at the moment, converting between RGB and CMYK and back first uses CMY internally.

for example..

php code:
 
 
class CMY {
  function toRGB() {
   return $this->toCMY()->toCMYK();
 }
 
}
 
class RGB {
  function toCMYK() {
    return $this->toCMY()->toRGB();
  }
}
 


I wonder if I can find a formula that does this all in a different way.. Hm.
0/0
 Reply   Quote More 

 From:  Dan (HERMAND)  
 To:  koswix     
39627.16 In reply to 39627.14 
:(
0/0
 Reply   Quote More 

 From:  Mikee  
 To:  ALL
39627.17 

Hmm.

 

Slowly started moving it over to namespaced PHP5.3 with some unit tests and whatnot.

 

https://github.com/mikeemoo/ColorJizz-PHP

 

Still a long way to do, and a whole load of comments to add!

 

It's not very extendable the way it is, though. Thinking of restructuring it so it's got more of a plugin-style system going on.

0/0
 Reply   Quote More 

 From:  Matt  
 To:  Mikee     
39627.18 In reply to 39627.17 

Your extensibility looks fine, I wouldn't bother trying to make a plug-in style system, it'll just turn into a hideous mess of over-complicated checks involving method_exists and depending on how you do it, file_exists too, all of which will only slow it down.

 

The only thing I might do is make the arguments to your class methods all objects so you can type hint them and thus enforce them to be something more robust than PHP's crappy loose typing.

 

If you want to make it really easy to extend, and as you're targeting PHP 5.3, (you'll know this already of course) just make sure you're using the 'static' keyword when calling static functions and not self so they too can be overloaded / inherited. Also put things into suitably small chunks in properly scoped methods and well, that's about it.

doohicky

0/0
 Reply   Quote More 

Reply to All    
 

1–18

Rate my interest:

Adjust text size : Smaller 10 Larger

Beehive Forum 1.5.2 |  FAQ |  Docs |  Support |  Donate! ©2002 - 2024 Project Beehive Forum

Forum Stats