Class: Phys::Quantity

Inherits:
Object
  • Object
show all
Includes:
UnitsNumericMixin
Defined in:
lib/phys/units/quantity.rb,
lib/phys/units/mixin.rb

Overview

Phys::Quantity is the primary class of Phys-Units library, intended to be manipulated by users. This class represents Physical Quantities with a Unit of measurement. It contains Value and Unit.

  • Value of the quantity is given as the first parameter of Quantity constructor (alias is Quantity[]). It must be a class instance having arithmetic methods, but it is not necessary to be a Numeric. This is a duck typing way.

    Phys::Quantity[2.5,"miles"].value    #=> 2.5
    Phys::Quantity[NArray.float(5).indgen,"miles"].want("m").value
    #=> NArray.float(5):
        [ 0.0, 1609.34, 3218.69, 4828.03, 6437.38 ]
    
  • Unit is an instance of Phys::Unit class. It is created from the second argument of Quantity constructor. See document of Phys::Unit.

    Phys::Quantity[2.5,"miles"].unit #=> #<Phys::Unit 1609.344,{"m"=>1},@expr="5280 ft">
    

Examples:

require 'phys/units'
Q = Phys::Quantity

Q[1.23,'km'] + Q[4.56,'m']    #=> Phys::Quantity[1.23456,'km']
Q[123,'mile'] / Q[2,'hr']     #=> Phys::Quantity[61,'mile/hr']
Q[61,'miles/hr'].want('m/s')  #=> Phys::Quantity[27.26944,'m/s']
Q[1.0,'are'] == Q[10,'m']**2  #=> true
Q[70,'tempF'] + Q[10,'degC']  #=> Phys::Quantity[88,'tempF']
Q[20,'tempC'].want('tempF')   #=> Phys::Quantity[68,'tempF']
Math.cos(Q[60,'degree'].to_f) #=> 0.5

See Also:

Direct Known Subclasses

Quanty

Constant Summary collapse

@@verbose_inspect =
false

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from UnitsNumericMixin

#call, #method_missing, #method_missing_units_alias

Constructor Details

#initialize(value, expr, unit = nil) ⇒ Quantity #initialize(value, unit) ⇒ Quantity #initialize(value) ⇒ Quantity

Initialize a new quantity.

Overloads:

  • #initialize(value, expr, unit = nil) ⇒ Quantity

    Parameters:

    • value (Object)

      Value of quantity.

    • expr (String, Symbol)

      Unit expression.

    • unit (Phys::Unit) (defaults to: nil)

      If exists, this parameter is used as the unit of new quantity.

  • #initialize(value, unit) ⇒ Quantity

    Parameters:

    • value (Object)

      Value of quantity.

    • unit (Phys::Unit)

      This parameter is used as the unit of new quantity.

  • #initialize(value) ⇒ Quantity

    Parameters:

    • value (Object)

      Value of a dimensionless quantity.

Raises:

  • (TypeError)

    if invalid arg types.

  • (Phys::UnitError)

    if unit conversion is failed.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/phys/units/quantity.rb', line 81

def initialize(value,expr=nil,unit=nil)
  @value = value
  case expr
  when String, Symbol
    @expr = expr.to_s.strip
    @expr = nil if @expr==''
    @unit = unit
  when NilClass
    @expr = nil
    @unit = unit
  when Unit
    raise ArgumentError,"Wrong # of argument" if unit
    @expr = nil
    @unit = expr
  else
    raise ArgumentError,"Second argument is invalid: #{expr.inspect}"
  end
  case @unit
  when NilClass
    @unit = Unit.parse(@expr||1)
  when Unit
  else
    raise ArgumentError, "Third argument is invalid: #{@unit.inspect}"
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Phys::UnitsNumericMixin

Instance Attribute Details

#exprString (readonly)

Unit expression. Given as the second parameter of the Quantity constructor.

Returns:

  • (String)


115
116
117
# File 'lib/phys/units/quantity.rb', line 115

def expr
  @expr
end

#unitPhys::Unit (readonly)

Unit of the quantity. Instance of Phys::Unit class.

Returns:



119
120
121
# File 'lib/phys/units/quantity.rb', line 119

def unit
  @unit
end

#valueObject (readonly) Also known as: val

Value of the quantity. Instance of classes with same arithmetic methods as Numeric.

Returns:

  • (Object)


110
111
112
# File 'lib/phys/units/quantity.rb', line 110

def value
  @value
end

Class Method Details

.[](value, unit = nil) ⇒ Phys::Quantity

Alias to Phys::Quantity.new.

Parameters:

  • value (Object)

    Value of quantity.

  • unit (String, Symbol, Phys::Unit) (defaults to: nil)
    • If unit String or Symbol, it is regarded as a unit expression (to be parsed later).

    • If unit is Phys::Unit, it is used as the unit of new quantity.

    • If unit is not provided, the quantity is regarded as dimensionless.

Returns:

Raises:

  • (TypeError)

    if invalid arg types.

  • (Phys::UnitError)

    if unit conversion is failed.



63
64
65
# File 'lib/phys/units/quantity.rb', line 63

def [](value,unit=nil)
  self.new(value,unit)
end

Instance Method Details

#%(other) ⇒ Object Also known as: modulo

Modulo.

  • If the other param is Phys::Quantity, other is converted to the unit of self, and returns modulo of values.

  • If the other param is not Phys::Quantity, other is regarded as dimensionless, and returns modulo of Phys::Quantity.

Parameters:

  • other (Object)

Returns:

  • (Object)

    modulo

Raises:



453
454
455
456
457
458
459
# File 'lib/phys/units/quantity.rb', line 453

def %(other)
  if Quantity===other
    @value % @unit.convert(other)
  else
    self.class.new( @value % other, @expr, @unit )
  end
end

#*(other) ⇒ Phys::Quantity

Multiplication. If the other param is not Phys::Quantity, other is regarded as a dimensionless value. The values and units are multiplied respectively.

Parameters:

  • other (Object)

Returns:

Raises:



354
355
356
357
358
359
360
361
362
# File 'lib/phys/units/quantity.rb', line 354

def *(other)
  if Quantity===other
    a = [self.enclose_expr, other.enclose_expr]
    a.delete(nil)
    self.class.new( @value*other.value, a.join(' '), @unit*other.unit )
  else
    self.class.new( @value*other, @expr, @unit )
  end
end

#**(n) ⇒ Phys::Quantity

Exponentiation.

Parameters:

  • n (Numeric)

Returns:

Raises:



311
312
313
314
315
316
317
318
319
320
# File 'lib/phys/units/quantity.rb', line 311

def **(n)
  if @expr.nil?
    expr = nil
  elsif /^[A-Za-z_]+$/o =~ @expr
    expr = @expr+'^'+n.to_s
  else
    expr = '('+@expr+')^'+n.to_s+''
  end
  self.class.new( @value**n, expr, @unit**n )
end

#+(other) ⇒ Phys::Quantity

Addition. Before the operation, it converts other to the unit of self.

  • If the other param is Phys::Quantity, other is converted to the unit of self.

  • If the other param is not Phys::Quantity, both params must be dimensionless.

Parameters:

  • other (Object)

Returns:

Raises:



159
160
161
162
# File 'lib/phys/units/quantity.rb', line 159

def +(other)
  val = @value + @unit.convert_scale(other)
  self.class.new( val, @expr, @unit )
end

#+@Phys::Quantity

Unary Plus. Returns self.

Returns:



223
224
225
# File 'lib/phys/units/quantity.rb', line 223

def +@
  self.class.new(  @value, @expr, @unit )
end

#-(other) ⇒ Phys::Quantity

Subtraction. Before the operation, it converts other to the unit of self.

  • If the other param is Phys::Quantity, other is converted to the unit of self.

  • If the other param is not Phys::Quantity, both params must be dimensionless.

Parameters:

  • other (Object)

Returns:

Raises:



174
175
176
177
# File 'lib/phys/units/quantity.rb', line 174

def -(other)
  val = @value - @unit.convert_scale(other)
  self.class.new( val, @expr, @unit )
end

#-@Phys::Quantity

Unary Minus. Returns a quantity with negative value in the same unit of self.

Returns:



230
231
232
# File 'lib/phys/units/quantity.rb', line 230

def -@
  self.class.new( -@value, @expr, @unit )
end

#/(other) ⇒ Phys::Quantity

Division. If the other param is not Phys::Quantity, other is regarded as a dimensionless value. The values and units are divided respectively. Note that the method of the value’s class is used.

Examples:

Phys::Quantity[3,:m]/2 #=> Phys::Quantity[1,"m"]

Parameters:

  • other (Object)

Returns:

Raises:



375
376
377
378
379
380
381
382
383
# File 'lib/phys/units/quantity.rb', line 375

def /(other)
  if Quantity===other
    a = [self.enclose_expr, other.enclose_expr_div]
    a.delete(nil)
    self.class.new( @value/other.value, a.join, @unit/other.unit )
  else
    self.class.new( @value/other, @expr, @unit )
  end
end

#<(other) ⇒ Boolean

Comparison. Returns true if self is less than other. Before the comparison, it converts other to the unit of self.

Parameters:

Returns:

  • (Boolean)

Raises:



281
282
283
# File 'lib/phys/units/quantity.rb', line 281

def < (other)
  @value < @unit.convert(other)
end

#<=(other) ⇒ Boolean

Comparison. Returns true if self is less-than or equal-to other. Before the comparison, it converts other to the unit of self.

Parameters:

Returns:

  • (Boolean)

Raises:



272
273
274
# File 'lib/phys/units/quantity.rb', line 272

def <= (other)
  @value <= @unit.convert(other)
end

#<=>(other) ⇒ Integer

Comparison of quantities. Before the comparison, it converts other to the unit of self.

Parameters:

Returns:

  • (Integer)

Raises:



239
240
241
# File 'lib/phys/units/quantity.rb', line 239

def <=> (other)
  @value <=> @unit.convert(other)
end

#==(other) ⇒ Boolean

Equality. Returns true if self has the same value as other. Before the comparison, it converts other to the unit of self.

Parameters:

Returns:

  • (Boolean)


247
248
249
250
251
252
253
254
255
256
# File 'lib/phys/units/quantity.rb', line 247

def == (other)
  if Quantity===other
    @unit.conformable?(other.unit) &&
      @value == @unit.convert(other)
  elsif @unit.dimensionless?
    @unit.convert_value_to_base_unit(@value) == other
  else
    false
  end
end

#===(x) ⇒ Boolean Also known as: conformable?, compatible?, conversion_allowed?

Conformability of quantity. Returns true if unit conversion between self and x is possible.

Parameters:

  • x (Object)

    other object (Unit or Quantity or Numeric or something else)

Returns:

  • (Boolean)


557
558
559
560
561
562
563
564
565
566
567
568
# File 'lib/phys/units/quantity.rb', line 557

def ===(x)
  case x
  when Unit
    unit === x
  when Quantity
    unit === x.unit
  when Numeric
    unit.dimensionless?
  else
    false
  end
end

#>(other) ⇒ Boolean

Comparison. Returns true if self is greater than other. Before the comparison, it converts other to the unit of self.

Parameters:

Returns:

  • (Boolean)

Raises:



290
291
292
# File 'lib/phys/units/quantity.rb', line 290

def > (other)
  @value > @unit.convert(other)
end

#>=(other) ⇒ Boolean

Comparison. Returns true if self is greater-than or equal-to other. Before the comparison, it converts other to the unit of self.

Parameters:

Returns:

  • (Boolean)

Raises:



263
264
265
# File 'lib/phys/units/quantity.rb', line 263

def >= (other)
  @value >= @unit.convert(other)
end

#absPhys::Quantity

Absolute. Returns a quantity in the same unit of self.

Returns:



181
182
183
# File 'lib/phys/units/quantity.rb', line 181

def abs
  self.class.new( @value.abs, @expr, @unit )
end

#abs2Phys::Quantity

Square. Returns a quantity in squared unit of self.

Returns:



187
188
189
# File 'lib/phys/units/quantity.rb', line 187

def abs2
  self**2
end

#ceilPhys::Quantity

Ceil. Returns a quantity with the smallest Integer value greater than or equal to self value, in the same unit of self.

Returns:



194
195
196
# File 'lib/phys/units/quantity.rb', line 194

def ceil
  self.class.new( @value.ceil, @expr, @unit )
end

#close_to(other, epsilon = Float::EPSILON) ⇒ Boolean

Closeness. Returns true if

(self-other).abs <= (self.abs+other.abs) * epsilon

Before the comparison, it converts other to the unit of self.

Parameters:

  • other (Phys::Quantity)
  • epsilon (Numeric) (defaults to: Float::EPSILON)

Returns:

  • (Boolean)

Raises:



301
302
303
304
305
# File 'lib/phys/units/quantity.rb', line 301

def close_to(other,epsilon=Float::EPSILON)
  other_value = @unit.convert(other)
  abs_sum = @value.abs+other_value.abs
  (@value-other_value).abs <= abs_sum*epsilon
end

#coerce(other) ⇒ Array

Returns:

  • (Array)


484
485
486
# File 'lib/phys/units/quantity.rb', line 484

def coerce(other)
  [ self.class.new(other), self ]
end

#div(other) ⇒ Object

Division without Modulo.

  • If the other param is Phys::Quantity, other is converted to the unit of self, and returns div of values.

  • If the other param is not Phys::Quantity, other is regarded as dimensionless, and returns div of Phys::Quantity.

Parameters:

  • other (Object)

Returns:

  • (Object)

    div

Raises:



415
416
417
418
419
420
421
# File 'lib/phys/units/quantity.rb', line 415

def div(other)
  if Quantity===other
    @value.div( @unit.convert(other) )
  else
    self.class.new( @value.div(other), @expr, @unit )
  end
end

#divmod(other) ⇒ Array

Division with Modulo.

  • If the other param is Phys::Quantity, other is converted to the unit of self, and returns divmod of values.

  • If the other param is not Phys::Quantity, other is regarded as dimensionless, and returns divmod of Phys::Quantity.

Parameters:

  • other (Object)

Returns:

  • (Array)

    result of divmod, an array of [quotient, modulo].

Raises:



473
474
475
476
477
478
479
480
481
# File 'lib/phys/units/quantity.rb', line 473

def divmod(other)
  if Quantity===other
    @value.divmod( @unit.convert(other) )
  else
    d,m = @value.divmod(other)
    [ self.class.new( d, @expr, @unit ),
      self.class.new( m, @expr, @unit ) ]
  end
end

#floorPhys::Quantity

Floor. Returns a quantity with the largest integer value less than or equal to self value, in the same unit of self.

Returns:



210
211
212
# File 'lib/phys/units/quantity.rb', line 210

def floor
  self.class.new( @value.floor, @expr, @unit )
end

#inspectString

Inspect String.

Returns:

  • (String)


547
548
549
550
551
552
# File 'lib/phys/units/quantity.rb', line 547

def inspect
  expr = @expr || @unit.expr
  expr = (expr) ? ","+expr.inspect : ""
  sufx = (@@verbose_inspect) ? " "+@unit.inspect : ""
  self.class.to_s+"["+Unit::Utils.num_inspect(@value)+expr+"]"+sufx
end

#quo(other) ⇒ Phys::Quantity Also known as: fdiv

Division more correctly. If the other param is not Phys::Quantity, other is regarded as a dimensionless value. The values and units are divided respectively.

Parameters:

  • other (Object)

Returns:

Raises:



393
394
395
396
397
398
399
400
401
# File 'lib/phys/units/quantity.rb', line 393

def quo(other)
  if Quantity===other
    a = [self.enclose_expr, other.enclose_expr_div]
    a.delete(nil)
    self.class.new( @value.quo(other.value), a.join, @unit/other.unit )
  else
    self.class.new( @value.quo(other), @expr, @unit )
  end
end

#remainder(other) ⇒ Object

Remainder.

  • If the other param is Phys::Quantity, other is converted to the unit of self, and returns remainder of values.

  • If the other param is not Phys::Quantity, other is regarded as dimensionless, and returns remainder of Phys::Quantity.

Parameters:

  • other (Object)

Returns:

  • (Object)

    remainder

Raises:



434
435
436
437
438
439
440
# File 'lib/phys/units/quantity.rb', line 434

def remainder(other)  #:nodoc: used internally
  if Quantity===other
    @value.remainder( @unit.convert(other) )
  else
    self.class.new( @value.remainder(other), @expr, @unit )
  end
end

#round(ndigits = nil) ⇒ Phys::Quantity

Round. Rounds self value to a given precision in decimal digits (default 0 digits). Returns a quantity with the rounded value in the same unit of self.

Returns:



202
203
204
205
# File 'lib/phys/units/quantity.rb', line 202

def round(ndigits=nil)
  val = ndigits ? @value.round(ndigits) : @value.round
  self.class.new( val, @expr, @unit )
end

#to_base_unitPhys::Quantity Also known as: to_si, to_SI

Conversion to base unit. Returns the quantity converted to a base unit.

Returns:

Raises:



492
493
494
495
496
497
# File 'lib/phys/units/quantity.rb', line 492

def to_base_unit
  unit = @unit.base_unit
  val  = unit.convert(self)
  expr = unit.unit_string
  self.class.new( val, expr, unit )
end

#to_fFloat Also known as: to_float

Conversion to Float.

Returns:

  • (Float)

Raises:



512
513
514
# File 'lib/phys/units/quantity.rb', line 512

def to_f
  to_numeric.to_f
end

#to_iInteger Also known as: to_int, to_integer

Conversion to Integer.

Returns:

  • (Integer)

Raises:



520
521
522
# File 'lib/phys/units/quantity.rb', line 520

def to_i
  to_numeric.to_i
end

#to_numericNumeric Also known as: to_num

Conversion to Numeric.

Returns:

  • (Numeric)

Raises:



504
505
506
# File 'lib/phys/units/quantity.rb', line 504

def to_numeric
  @unit.to_numeric * @value
end

#to_rRational Also known as: to_rational

Conversion to Rational.

Returns:

  • (Rational)

Raises:



529
530
531
# File 'lib/phys/units/quantity.rb', line 529

def to_r
  to_numeric.to_r
end

#to_sString

Conversion to String.

Returns:

  • (String)


536
537
538
539
540
541
542
543
# File 'lib/phys/units/quantity.rb', line 536

def to_s
  if @expr
    expr = ",'" +@expr+"'"
  else
    expr = ""
  end
  self.class.to_s+"["+Unit::Utils.num_inspect(@value)+expr+"]"
end

#truncatePhys::Quantity

Truncate. Returns a quantity with the value truncated to an integer, in the same unit of self.

Returns:



217
218
219
# File 'lib/phys/units/quantity.rb', line 217

def truncate
  self.class.new( @value.truncate, @expr, @unit )
end

#want(unit = nil) ⇒ Phys::Quantity Also known as: convert, >>

Conversion to a quantity in another unit.

Parameters:

  • unit (String, Symbol, Unit, Quantity) (defaults to: nil)

    unit expression.

Returns:

Raises:



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/phys/units/quantity.rb', line 126

def want(unit=nil)
  case unit
  when Unit
    expr = unit.expr
  when Quantity
    expr = unit.expr
    unit = unit.unit
  when String,Symbol
    expr = unit
    unit = Unit.parse(expr)
  when Numeric
    unit = Unit.cast(unit)
  when NilClass
    unit = Unit.cast(1)
  else
    raise TypeError, "invalid argument: #{unit.inspect}"
  end
  val = unit.convert(self)
  self.class.new( val, expr, unit )
end