Multiple Unit Scalar

S

Stephan Rose

In one of the applications I am developing I have need of working with
numbers in varying unit system. I might be adding 5 mil to 1 inch or
whatever.

What I have come up with works really well, however...it moves about
as fast as a honda civic trying to tow a semi truck.

The basic definition looks like this:

public struct ScalarGeneric : IScalar
{
private decimal value;
private ScalarUnit unit;

// Properties, constructors, operators, etc. skipped
}

Using decimal for precision and to avoid floating point issues.

The problem essentially is this that in my operator overloads for +,
-, etc. before I can perform the actual operation I need to obviously
check what unit space my first operand is, and then convert the second
operand to match the first, then perform the operation and return the
result in the matched unit space.

So what I end up with is, is something like this:

public static ScalarGeneric operator + (ScalarGeneric a, IScalar b)
{
switch(a.unit)
{
case ScalarUnit.Centimeter:
return new ScalarGeneric(a.Value +
b.ToCentimeters().Value, ScalarUnit.Centimeter); case
ScalarUnit.Inch:
return new ScalarGeneric(a.Value +
b.ToInch().Value, ScalarUnit.Inch);
case ScalarUnit.Mil:
return new ScalarGeneric(a.Value +
b.ToMil().Value, ScalarUnit.Mil);
case ScalarUnit.Millimeter:
return new ScalarGeneric(a.Value +
b.ToMillimeters().Value, ScalarUnit.Millimeter);
case ScalarUnit.Degree:
return new ScalarGeneric(a.Value +
b.ToDegree().Value, ScalarUnit.Degree);
case ScalarUnit.Radian:
return new ScalarGeneric(a.Value +
b.ToRadian().Value, ScalarUnit.Radian);
default:
throw new System.InvalidOperationException();
}
}


And so on for other operators.

Bottom line, this works really well but isn't all that fast. I have
been trying to find ways to optimize this as even a small improvement
would make a huge difference as I can easily end up with thousands of
ops when redrawing a full scene. So far though I have been drawing a
blank on how / if I can manage to get any additional performance out
of this.

If anyone has any suggestions I would love to see them!

Thanks,

--
Stephan
2003 Yamaha R6

kimi no koto omoidasu hi
nante nai no wa
kimi no koto wasureta toki ga nai kara
 
P

Paul Henderson

In one of the applications I am developing I have need of working with
numbers in varying unit system. I might be adding 5 mil to 1 inch or
whatever.
[snip]
The problem essentially is this that in my operator overloads for +,
-, etc. before I can perform the actual operation I need to obviously
check what unit space my first operand is, and then convert the second
operand to match the first, then perform the operation and return the
result in the matched unit space.

Using a switch block as you currently are is definitely not a nice
solution...

Instead, one method would be to always store values of the same
dimension in the same basis [e.g. always meters for lengths, always
radians for angles, etc.], and then you need to perform no [or at least
very few] conversions when doing calculations; just operate on the raw
values and set the unit of the result to match that of the first
operand. Only when you need to show the data to the user must you then
multiply by the conversion factor corresponding to the required unit.
If your system is performing lots of heavy calculation and relatively
little user interaction, this should speed things up considerably.

-- PH
 
G

GhostInAK

Hello Paul,

You may also consider using a more generic approach. Define your class/interface
with two properties: .Value, and .Scale... Then pick an arbitrary scale
against which everything else gets scaled. Lets say that you are using US
measurements.. and that the US Inch is your basic unit of measure.. Then
an Inch would look like:

Inch
.Scale = 1
.Value = whatever

And a Foot would look like:

Foot
.Scale = 12
.Value = whatever

Now when you go to overload your operatos you can do (assume you want the
result in the first parameter's (Value1) scale):

For Addition:
return (Value1.Value / Value1.Scale) + (Value2.Value / Value2.Scale)


This method should work well as long as you group your units into logical
groups.. (ie, don't go mixing Volume measurements (cubic feet) with time
measurements (seconds).. they just wont make sense and you'll get gibberish
back)

-Boo
In one of the applications I am developing I have need of working
with
numbers in varying unit system. I might be adding 5 mil to 1 inch or
whatever.
[snip]
The problem essentially is this that in my operator overloads for +,
-, etc. before I can perform the actual operation I need to obviously
check what unit space my first operand is, and then convert the
second
operand to match the first, then perform the operation and return the
result in the matched unit space.
Using a switch block as you currently are is definitely not a nice
solution...

Instead, one method would be to always store values of the same
dimension in the same basis [e.g. always meters for lengths, always
radians for angles, etc.], and then you need to perform no [or at
least very few] conversions when doing calculations; just operate on
the raw values and set the unit of the result to match that of the
first operand. Only when you need to show the data to the user must
you then multiply by the conversion factor corresponding to the
required unit. If your system is performing lots of heavy calculation
and relatively little user interaction, this should speed things up
considerably.
 
S

Stephan Rose

Hello Paul,

You may also consider using a more generic approach. Define your class/interface
with two properties: .Value, and .Scale... Then pick an arbitrary scale
against which everything else gets scaled. Lets say that you are using US
measurements.. and that the US Inch is your basic unit of measure.. Then
an Inch would look like:

Inch
.Scale = 1
.Value = whatever

And a Foot would look like:

Foot
.Scale = 12
.Value = whatever

Now when you go to overload your operatos you can do (assume you want the
result in the first parameter's (Value1) scale):

For Addition:
return (Value1.Value / Value1.Scale) + (Value2.Value / Value2.Scale)


This method should work well as long as you group your units into logical
groups.. (ie, don't go mixing Volume measurements (cubic feet) with time
measurements (seconds).. they just wont make sense and you'll get gibberish
back)

-Boo

Thanks everyone for your replies.

I really like that second idea with the scale, I think I might go that
route.


--
Stephan
2003 Yamaha R6

kimi no koto omoidasu hi
nante nai no wa
kimi no koto wasureta toki ga nai kara
 
G

GhostInAK

Hello Stephan,

I thought this sounded like a fun project so I started writing it myself
as well. I have run into a few bumps along the way.. mainly due to bad planning.
The system of a single Scale value works well for those units whose system
can be converted using a simple scaling approach. For other systems (eg,
temperature conversions) this system doesnt work so well.

Here's my overloaded addition operator for the Scale method:

'
' Will return a UnitOfMeasure in tValueOne's scale.
'
Public Shared Operator +(ByVal tValueOne As UnitOfMeasure, ByVal tValueTwo
As UnitOfMeasure) As UnitOfMeasure

Dim tReturn As UnitOfMeasure = New UnitOfMeasure

tReturn.Scale = tValueOne.Scale
tReturn.Value = ((tValueOne.Value * tValueOne.Scale) + (tValueTwo.Value
* tValueTwo.Scale)) / tValueOne.Scale

Return tReturn

End Operator
 

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

Top