fixed_point 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.md +14 -0
- data/LICENSE +25 -0
- data/README.md +35 -0
- data/Rakefile +11 -0
- data/lib/fixed_point.rb +13 -0
- data/lib/fixed_point/fixdt.rb +8 -0
- data/lib/fixed_point/format.rb +55 -0
- data/lib/fixed_point/number.rb +312 -0
- data/spec/fixed_point_negative_spec.rb +52 -0
- data/spec/fixed_point_spec.rb +311 -0
- data/spec/spec_helper.rb +4 -0
- metadata +77 -0
data/HISTORY.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2011, Morgan Prior
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
* Redistributions of source code must retain the above copyright
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
8
|
+
* Redistributions in binary form must reproduce the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer in the
|
10
|
+
documentation and/or other materials provided with the distribution.
|
11
|
+
* Neither the name of the organization nor the
|
12
|
+
names of its contributors may be used to endorse or promote products
|
13
|
+
derived from this software without specific prior written permission.
|
14
|
+
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
16
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
17
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
19
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
20
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
21
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
22
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
23
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
24
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
FixedPoint
|
2
|
+
============
|
3
|
+
|
4
|
+
For modeling fixed point signed and unsigned data types and having nice function for printing hex and binary forms.
|
5
|
+
|
6
|
+
Install
|
7
|
+
-------
|
8
|
+
|
9
|
+
gem install fixed_point
|
10
|
+
|
11
|
+
Usage
|
12
|
+
-----
|
13
|
+
|
14
|
+
Checkout the examples folder, but here are a few:
|
15
|
+
|
16
|
+
require 'fixed_point'
|
17
|
+
|
18
|
+
#Create fixed point format, Signed, 12 integer bits, 4 fractional bits
|
19
|
+
format = FixedPoint::Format.new(1, 12, 4)
|
20
|
+
|
21
|
+
#Create fixed_point with value 1024.75
|
22
|
+
fix_num = FixedPoint::Number.new(1024.75, format )
|
23
|
+
|
24
|
+
puts fix_num.to_f # Float
|
25
|
+
puts fix_num.to_h # Hexadecimal
|
26
|
+
puts fix_num.to_b # Binary
|
27
|
+
|
28
|
+
TODO
|
29
|
+
----
|
30
|
+
|
31
|
+
|
32
|
+
LICENSE
|
33
|
+
-------
|
34
|
+
|
35
|
+
See the LICENSE file
|
data/Rakefile
ADDED
data/lib/fixed_point.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module FixedPoint
|
2
|
+
VERSION = '0.1.0'
|
3
|
+
end
|
4
|
+
|
5
|
+
begin
|
6
|
+
require_relative 'fixed_point/format'
|
7
|
+
require_relative 'fixed_point/fixdt'
|
8
|
+
require_relative 'fixed_point/number'
|
9
|
+
rescue
|
10
|
+
require 'fixed_point/format'
|
11
|
+
require 'fixed_point/fixdt'
|
12
|
+
require 'fixed_point/number'
|
13
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module FixedPoint
|
2
|
+
|
3
|
+
class Format
|
4
|
+
|
5
|
+
attr_reader :signed, :int_bits, :frac_bits
|
6
|
+
|
7
|
+
# Calculated attributes
|
8
|
+
attr_reader :width
|
9
|
+
attr_reader :resolution, :max_value, :min_value
|
10
|
+
attr_reader :max_int_signed, :max_int_unsigned
|
11
|
+
attr_reader :max_frac
|
12
|
+
attr_reader :max_signed, :max_unsigned
|
13
|
+
|
14
|
+
def initialize(signed, int_bits, frac_bits)
|
15
|
+
@signed = signed
|
16
|
+
@int_bits = int_bits
|
17
|
+
@frac_bits = frac_bits
|
18
|
+
|
19
|
+
calculate_attributes(signed, int_bits, frac_bits)
|
20
|
+
end
|
21
|
+
|
22
|
+
def signed?
|
23
|
+
(@signed == 1)
|
24
|
+
end
|
25
|
+
|
26
|
+
#Format Should hold the maxim possible values
|
27
|
+
#not part of number (Value)
|
28
|
+
def calculate_attributes(signed, int_bits, frac_bits)
|
29
|
+
@width = int_bits + frac_bits
|
30
|
+
|
31
|
+
#Calculate Number ranges
|
32
|
+
@resolution = 2**(-@frac_bits)
|
33
|
+
@max_frac = 1 - 2**(-@frac_bits)
|
34
|
+
@max_int_signed = ( 2**(@int_bits - 1) - 1)
|
35
|
+
@max_int_unsigned = ( 2**@int_bits - 1)
|
36
|
+
@max_signed = @max_int_signed + @max_frac
|
37
|
+
@max_unsigned = @max_int_unsigned + @max_frac
|
38
|
+
|
39
|
+
@min_signed = (-2**(@int_bits-1))
|
40
|
+
@min_unsigned = 0
|
41
|
+
|
42
|
+
#Set Max/Min values
|
43
|
+
if signed?
|
44
|
+
@max_value = @max_signed
|
45
|
+
@min_value = @min_signed
|
46
|
+
else
|
47
|
+
@max_value = @max_unsigned
|
48
|
+
@min_value = @min_unsigned
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end #module FixedPoint
|
@@ -0,0 +1,312 @@
|
|
1
|
+
module FixedPoint
|
2
|
+
|
3
|
+
class Number
|
4
|
+
attr_reader :source #Input value
|
5
|
+
attr_reader :format
|
6
|
+
|
7
|
+
############################################
|
8
|
+
#### Note
|
9
|
+
## All methods which set the @source value
|
10
|
+
## must also set the @quantised value.
|
11
|
+
## Every thing else is calculated on the fly
|
12
|
+
## based on those 2 values
|
13
|
+
############################################
|
14
|
+
|
15
|
+
|
16
|
+
####################################
|
17
|
+
### Init
|
18
|
+
####################################
|
19
|
+
def initialize(number, input_format=Format.new(1,12,20), decimal_mark=".")
|
20
|
+
@source = number
|
21
|
+
@format = input_format
|
22
|
+
@decimal_mark = decimal_mark
|
23
|
+
|
24
|
+
@warnings = false
|
25
|
+
|
26
|
+
#Now construct values based on config data
|
27
|
+
@quantised = quantise_value( source )
|
28
|
+
end
|
29
|
+
|
30
|
+
####################################
|
31
|
+
### Number overflow/underflow flags
|
32
|
+
####################################
|
33
|
+
def overflow?
|
34
|
+
@overflow
|
35
|
+
end
|
36
|
+
|
37
|
+
def underflow?
|
38
|
+
@underflow
|
39
|
+
end
|
40
|
+
|
41
|
+
####################################
|
42
|
+
### Methods to return number formats
|
43
|
+
####################################
|
44
|
+
def bin
|
45
|
+
binary
|
46
|
+
end
|
47
|
+
|
48
|
+
def hex
|
49
|
+
hexadecimal
|
50
|
+
end
|
51
|
+
|
52
|
+
#To Binary form
|
53
|
+
def to_b
|
54
|
+
binary
|
55
|
+
end
|
56
|
+
|
57
|
+
#To Hexadecimal form
|
58
|
+
def to_h
|
59
|
+
hexadecimal
|
60
|
+
end
|
61
|
+
|
62
|
+
#To Floating Point form, quantised version of _source_
|
63
|
+
def to_f
|
64
|
+
@quantised
|
65
|
+
end
|
66
|
+
|
67
|
+
#To Integer, limited integer part of _source_
|
68
|
+
def to_i
|
69
|
+
@quantised.to_i
|
70
|
+
end
|
71
|
+
|
72
|
+
# Method returns fractional section of fixed point type
|
73
|
+
# not a to_ method as it is not representative of the whole number
|
74
|
+
def frac
|
75
|
+
(@quantised - to_i)
|
76
|
+
end
|
77
|
+
|
78
|
+
def fraction
|
79
|
+
frac
|
80
|
+
end
|
81
|
+
|
82
|
+
####################################
|
83
|
+
### Methods to calculate formats
|
84
|
+
####################################
|
85
|
+
def binary
|
86
|
+
#Take signed quantised value and create binary string
|
87
|
+
if (@quantised < 0) and fraction.nonzero?
|
88
|
+
# Fractional numbers not negative
|
89
|
+
# So the integer part is 1 less than other wise would be and add 1+frac
|
90
|
+
ret_bin_int = (@format.max_int_unsigned + to_i )
|
91
|
+
frac_value = 1 + fraction
|
92
|
+
end
|
93
|
+
|
94
|
+
if (@quantised < 0) and fraction.zero?
|
95
|
+
ret_bin_int = (@format.max_int_unsigned + to_i + 1 )
|
96
|
+
frac_value = fraction
|
97
|
+
end
|
98
|
+
|
99
|
+
if @quantised >= 0
|
100
|
+
ret_bin_int = self.to_i
|
101
|
+
frac_value = fraction
|
102
|
+
end
|
103
|
+
|
104
|
+
## Convert to binary String and extend to correct length
|
105
|
+
ret_bin_int = ret_bin_int.to_s(2).rjust(@format.int_bits, '0')
|
106
|
+
|
107
|
+
## Normalise Fractional (fractional bits shifted to appear as integer)
|
108
|
+
ret_bin_frac = Integer(frac_value * 2**@format.frac_bits)
|
109
|
+
ret_bin_frac = ret_bin_frac.to_s(2).rjust(@format.frac_bits, '0' )
|
110
|
+
|
111
|
+
#Decide if we need to add Decimal( Binary ) Point
|
112
|
+
if @format.frac_bits > 0
|
113
|
+
binary_string = ret_bin_int + @decimal_mark + ret_bin_frac
|
114
|
+
else
|
115
|
+
binary_string = ret_bin_int
|
116
|
+
end
|
117
|
+
|
118
|
+
return binary_string
|
119
|
+
end
|
120
|
+
|
121
|
+
def hexadecimal
|
122
|
+
#Clean Binary code (remove _ - . etc)
|
123
|
+
clean_binary = to_b.scan(/[01]/).join('')
|
124
|
+
|
125
|
+
#Convert to unsigned int then to hex
|
126
|
+
hex = clean_binary.to_i(2).to_s(16)
|
127
|
+
hex_chars = (@format.width/4.0).ceil
|
128
|
+
|
129
|
+
## Extend to the correct length
|
130
|
+
## Negative numbers will already have MSBs this if for small +VE
|
131
|
+
return hex.rjust(hex_chars, '0')
|
132
|
+
end
|
133
|
+
|
134
|
+
####################################
|
135
|
+
### Methods to set value from fixed point format
|
136
|
+
####################################
|
137
|
+
def binary=(text)
|
138
|
+
if text.match(/([01]*)(.?)([01]*)/ )
|
139
|
+
set_int = $1
|
140
|
+
int_bits = $1.size
|
141
|
+
|
142
|
+
@decimal_mark = $2
|
143
|
+
set_frac = $3
|
144
|
+
frac_bits = $3.size
|
145
|
+
|
146
|
+
#TODO Warn if the number of bits supplied does not match @format
|
147
|
+
|
148
|
+
## This should now create a new format type
|
149
|
+
# Do not change the Signed format as can not detect that from bit pattern
|
150
|
+
@format = Format.new(@format.signed, int_bits, frac_bits)
|
151
|
+
|
152
|
+
###########################
|
153
|
+
### Routine to generate source from binary
|
154
|
+
###########################
|
155
|
+
@source = 0.0
|
156
|
+
index = 0
|
157
|
+
set_int.reverse.each_char do |x|
|
158
|
+
if x == "1"
|
159
|
+
#If input is signed then MSB is negative
|
160
|
+
if ((index + 1) == @format.int_bits) and (@format.signed?)
|
161
|
+
@source = @source + -2**index
|
162
|
+
else
|
163
|
+
@source = @source + 2**index
|
164
|
+
end
|
165
|
+
end
|
166
|
+
index = index + 1
|
167
|
+
end
|
168
|
+
|
169
|
+
index = 1
|
170
|
+
set_frac.each_char do |x|
|
171
|
+
if x == "1"
|
172
|
+
@source = @source + 2**-index
|
173
|
+
end
|
174
|
+
index = index + 1
|
175
|
+
end
|
176
|
+
################################
|
177
|
+
|
178
|
+
## Set the Quantised value
|
179
|
+
@quantised = @source
|
180
|
+
|
181
|
+
return binary
|
182
|
+
else
|
183
|
+
puts "ERROR invalid input binary\(#{text}\)"
|
184
|
+
return nil
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
#def hex=( text )
|
189
|
+
#end
|
190
|
+
|
191
|
+
|
192
|
+
#TODO
|
193
|
+
#def log
|
194
|
+
#def log2
|
195
|
+
|
196
|
+
def warnings( val=true )
|
197
|
+
@warnings = val
|
198
|
+
end
|
199
|
+
|
200
|
+
private
|
201
|
+
|
202
|
+
def check_for_overflow_underflow( source, format)
|
203
|
+
overflow = false
|
204
|
+
underflow = false
|
205
|
+
|
206
|
+
#WARN +VE
|
207
|
+
if (source > 0) and (source > format.max_value)
|
208
|
+
puts "WARNING Maximum number is #{format.max_value} input was #{source}" if @warnings
|
209
|
+
overflow = true
|
210
|
+
end
|
211
|
+
|
212
|
+
##WARN -VE
|
213
|
+
if (source < 0) and (source < format.min_value)
|
214
|
+
puts "WARNING Minimum number is #{format.min_value} input was #{source}" if @warnings
|
215
|
+
underflow = true
|
216
|
+
end
|
217
|
+
|
218
|
+
return [overflow, underflow]
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
def quantise_value( source )
|
223
|
+
#Overflow / Underflow flags
|
224
|
+
@overflow, @underflow = check_for_overflow_underflow( source, @format)
|
225
|
+
|
226
|
+
## Create fractional only number
|
227
|
+
source_frac = source - source.to_i
|
228
|
+
|
229
|
+
#Logic for fractional negative numbers is different
|
230
|
+
if (( source < 0) and source_frac.nonzero? )
|
231
|
+
#Integer bits become 1 more negative
|
232
|
+
number_int = Integer( source )-1
|
233
|
+
|
234
|
+
#The @fractional part inverts so int+frac = original number
|
235
|
+
number_frac = ( source - number_int)
|
236
|
+
else
|
237
|
+
# Create Integer only number
|
238
|
+
number_int = source.to_i
|
239
|
+
|
240
|
+
#Fractional Part
|
241
|
+
number_frac = source_frac
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
if overflow?
|
246
|
+
if @format.signed?
|
247
|
+
number_int = @format.max_int_signed
|
248
|
+
number_frac = @format.max_frac
|
249
|
+
else
|
250
|
+
number_int = @format.max_int_unsigned
|
251
|
+
number_frac = @format.max_frac
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
if underflow?
|
256
|
+
if @format.signed?
|
257
|
+
number_int = 2**(@format.int_bits-1)
|
258
|
+
number_frac = 0
|
259
|
+
else
|
260
|
+
number_int = 0
|
261
|
+
number_frac = 0
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
##Roll the integer number over the number space so binary conversion gives correct Twos complement
|
266
|
+
if number_int < 0
|
267
|
+
number_int = @format.max_int_unsigned + (number_int + 1)
|
268
|
+
end
|
269
|
+
|
270
|
+
###################################
|
271
|
+
### Quantized Fractional value
|
272
|
+
###################################
|
273
|
+
# Normalise, represent as integer
|
274
|
+
# Fractional data is removed by the integer.
|
275
|
+
# We are only left with @format.frac_bits worth of data
|
276
|
+
number_frac_quant = (number_frac * 2**@format.frac_bits).to_i / (2**@format.frac_bits).to_f
|
277
|
+
|
278
|
+
# TODO Comment on what this is actually doing
|
279
|
+
# some sought of signed conversion
|
280
|
+
if (@source < 0) and number_frac_quant.nonzero?
|
281
|
+
number_int = number_int - @format.max_int_unsigned
|
282
|
+
number_frac_quant = number_frac_quant - 1
|
283
|
+
end
|
284
|
+
|
285
|
+
if (@source < 0) and number_frac_quant.zero?
|
286
|
+
number_int = number_int - @format.max_int_unsigned - 1
|
287
|
+
number_frac_quant = 0
|
288
|
+
end
|
289
|
+
|
290
|
+
return (number_int + number_frac_quant)
|
291
|
+
end ## quantise_input
|
292
|
+
|
293
|
+
|
294
|
+
|
295
|
+
|
296
|
+
|
297
|
+
## Taking methd out until covered by tests
|
298
|
+
#def normalised
|
299
|
+
# #This use to be only for positive numbers
|
300
|
+
#
|
301
|
+
# # This function shiftes the fixedpoint number
|
302
|
+
# # so it can be represented as an integer.
|
303
|
+
# return Integer((@quantised)*(2**@format.frac_bits))
|
304
|
+
#end
|
305
|
+
|
306
|
+
def FixedPoint_debug(msg)
|
307
|
+
if true == false
|
308
|
+
puts msg
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end #class number
|
312
|
+
end #module FixedPoint
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FixedPoint do
|
4
|
+
|
5
|
+
it "Negative Integers -1 " do
|
6
|
+
format = FixedPoint::Format.new(1,4,0)
|
7
|
+
fixt = FixedPoint::Number.new(-1.0, format, "_")
|
8
|
+
|
9
|
+
fixt.source.should == -1.0
|
10
|
+
fixt.to_f.should == -1.0
|
11
|
+
fixt.to_i.should == -1
|
12
|
+
fixt.frac.should == 0.0
|
13
|
+
fixt.to_h.should == "f"
|
14
|
+
fixt.to_b.should == "1111"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "Negative Integers -2 " do
|
18
|
+
format = FixedPoint::Format.new(1,4,0)
|
19
|
+
fixt = FixedPoint::Number.new(-2.0, format, "_")
|
20
|
+
|
21
|
+
fixt.source.should == -2.0
|
22
|
+
fixt.to_f.should == -2.0
|
23
|
+
fixt.to_i.should == -2
|
24
|
+
fixt.frac.should == 0.0
|
25
|
+
fixt.to_h.should == "e"
|
26
|
+
fixt.to_b.should == "1110"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "Negative Integers -1.5 " do
|
30
|
+
format = FixedPoint::Format.new(1,4,4)
|
31
|
+
fixt = FixedPoint::Number.new(-1.5, format, "_")
|
32
|
+
|
33
|
+
fixt.source.should == -1.5
|
34
|
+
fixt.to_f.should == -1.5
|
35
|
+
fixt.to_i.should == -1
|
36
|
+
fixt.frac.should == -0.5
|
37
|
+
fixt.to_h.should == "e8"
|
38
|
+
fixt.to_b.should == "1110_1000"
|
39
|
+
end
|
40
|
+
it "Negative Integers -2.25 " do
|
41
|
+
format = FixedPoint::Format.new(1,4,4)
|
42
|
+
fixt = FixedPoint::Number.new(-2.25, format, "_")
|
43
|
+
|
44
|
+
fixt.source.should == -2.25
|
45
|
+
fixt.to_f.should == -2.25
|
46
|
+
fixt.to_i.should == -2
|
47
|
+
fixt.frac.should == -0.25
|
48
|
+
fixt.to_h.should == "dc"
|
49
|
+
fixt.to_b.should == "1101_1100"
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,311 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# def initialize(number, Format.new(signed=1, int_bits=12, frac_bits=20), decimal_mark=".")
|
4
|
+
# source Input Number
|
5
|
+
# to_f quantised value as float
|
6
|
+
# to_i quantised value as integer
|
7
|
+
# frac fractional part of quantised value
|
8
|
+
# to_h quantised value as string formatted as hex
|
9
|
+
# to_b quantised value as string formatted as binary
|
10
|
+
#
|
11
|
+
|
12
|
+
describe FixedPoint do
|
13
|
+
|
14
|
+
it "Returns 0.0 for initalise of 0" do
|
15
|
+
fixt = FixedPoint::Number.new(0)
|
16
|
+
|
17
|
+
fixt.source.should == 0.0
|
18
|
+
fixt.to_f.should == 0.0
|
19
|
+
fixt.to_i.should == 0
|
20
|
+
fixt.frac.should == 0.0
|
21
|
+
fixt.to_h.should == "00000000"
|
22
|
+
fixt.to_b.should == "000000000000.00000000000000000000"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "Integers 0 " do
|
26
|
+
format = FixedPoint::Format.new(1,8,0)
|
27
|
+
fixt = FixedPoint::Number.new(7.0, format, "_")
|
28
|
+
|
29
|
+
fixt.source.should == 7.0
|
30
|
+
fixt.to_f.should == 7.0
|
31
|
+
fixt.to_i.should == 7
|
32
|
+
fixt.frac.should == 0.0
|
33
|
+
fixt.to_h.should == "07"
|
34
|
+
fixt.to_b.should == "00000111"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "Different Decimal Mark _ instead of ." do
|
38
|
+
format = FixedPoint::Format.new(1,12,20)
|
39
|
+
fixt = FixedPoint::Number.new(0, format, "_")
|
40
|
+
|
41
|
+
fixt.source.should == 0.0
|
42
|
+
fixt.to_f.should == 0.0
|
43
|
+
fixt.to_i.should == 0
|
44
|
+
fixt.frac.should == 0.0
|
45
|
+
fixt.to_h.should == "00000000"
|
46
|
+
fixt.to_b.should == "000000000000_00000000000000000000"
|
47
|
+
end
|
48
|
+
|
49
|
+
(1...20).to_a.reverse_each do |x|
|
50
|
+
int_bits = 12
|
51
|
+
it "Returns 0.0 for initalise of 0 with #{x} fractional bits" do
|
52
|
+
format = FixedPoint::Format.new(1, int_bits, x)
|
53
|
+
fixt = FixedPoint::Number.new(0, format)
|
54
|
+
#fixt = FixedPoint::Number.new(0,1,int_bits,x)
|
55
|
+
|
56
|
+
fixt.source.should == 0.0
|
57
|
+
fixt.to_f.should == 0.0
|
58
|
+
fixt.to_i.should == 0
|
59
|
+
fixt.frac.should == 0.0
|
60
|
+
#Calculate hex length and fill with 0's
|
61
|
+
hex = ""
|
62
|
+
hex_length = ((x.to_f+int_bits.to_f)/4).ceil
|
63
|
+
hex_length.times { hex += "0" }
|
64
|
+
fixt.to_h.should == hex
|
65
|
+
#Calculate binary fractional length and fill with 0's
|
66
|
+
lsbs = ""
|
67
|
+
x.times { lsbs += "0" }
|
68
|
+
fixt.to_b.should == "000000000000.#{lsbs}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
it "Zero fractional bits " do
|
74
|
+
format = FixedPoint::Format.new(1,12,0)
|
75
|
+
fixt = FixedPoint::Number.new(0, format, "_")
|
76
|
+
|
77
|
+
fixt.source.should == 0.0
|
78
|
+
fixt.to_f.should == 0.0
|
79
|
+
fixt.to_i.should == 0
|
80
|
+
fixt.frac.should == 0.0
|
81
|
+
fixt.to_h.should == "000"
|
82
|
+
fixt.to_b.should == "000000000000"
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
it "returns 2.5 for initalise of 2.5" do
|
87
|
+
fixt = FixedPoint::Number.new(2.5)
|
88
|
+
|
89
|
+
fixt.source.should == 2.5
|
90
|
+
fixt.to_f.should == 2.5
|
91
|
+
fixt.to_i.should == 2
|
92
|
+
fixt.frac.should == 0.5
|
93
|
+
fixt.to_h.should == "00280000"
|
94
|
+
fixt.to_b.should == "000000000010.10000000000000000000"
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
it "Truncates fractional numbers correctly" do
|
99
|
+
format = FixedPoint::Format.new(1,12,1)
|
100
|
+
fixt = FixedPoint::Number.new(2.501, format)
|
101
|
+
|
102
|
+
fixt.source.should == 2.501
|
103
|
+
fixt.to_f.should == 2.5
|
104
|
+
fixt.to_i.should == 2
|
105
|
+
fixt.frac.should == 0.5
|
106
|
+
fixt.to_h.should == "0005"
|
107
|
+
fixt.to_b.should == "000000000010.1"
|
108
|
+
end
|
109
|
+
|
110
|
+
##############################################
|
111
|
+
### Overflow Section
|
112
|
+
##############################################
|
113
|
+
it "Forced Overflow 4 Int Bits, 0 fractional bits " do
|
114
|
+
format = FixedPoint::Format.new(1, 4, 0)
|
115
|
+
fixt = FixedPoint::Number.new(2**3, format, "_")
|
116
|
+
|
117
|
+
fixt.source.should == 2**3
|
118
|
+
fixt.to_f.should == 2**3-1
|
119
|
+
fixt.to_i.should == 2**3-1
|
120
|
+
fixt.frac.should == 0.0
|
121
|
+
fixt.to_h.should == "7"
|
122
|
+
fixt.to_b.should == "0111"
|
123
|
+
fixt.overflow?.should == true
|
124
|
+
fixt.underflow?.should == false
|
125
|
+
end
|
126
|
+
|
127
|
+
it "Forced Overflow Zero fractional bits " do
|
128
|
+
format = FixedPoint::Format.new(1, 12, 0)
|
129
|
+
fixt = FixedPoint::Number.new(2**11, format, "_")
|
130
|
+
|
131
|
+
fixt.source.should == 2**11
|
132
|
+
fixt.to_f.should == 2**11-1
|
133
|
+
fixt.to_i.should == 2**11-1
|
134
|
+
fixt.frac.should == 0.0
|
135
|
+
fixt.to_h.should == "7ff"
|
136
|
+
fixt.to_b.should == "011111111111"
|
137
|
+
fixt.overflow?.should == true
|
138
|
+
fixt.underflow?.should == false
|
139
|
+
end
|
140
|
+
|
141
|
+
it "Forced Overflow 4 fractional bits " do
|
142
|
+
format = FixedPoint::Format.new(1, 12, 4)
|
143
|
+
fixt = FixedPoint::Number.new(2**11, format, ".")
|
144
|
+
|
145
|
+
max_fractional_value = (1.0/2) + (1.0/4) + (1.0/8) + (1.0/16)
|
146
|
+
|
147
|
+
fixt.source.should == 2**11
|
148
|
+
fixt.to_f.should == 2**11 -1 + max_fractional_value
|
149
|
+
fixt.to_i.should == 2**11 -1
|
150
|
+
fixt.frac.should == max_fractional_value
|
151
|
+
fixt.to_h.should == "7fff"
|
152
|
+
fixt.to_b.should == "011111111111.1111"
|
153
|
+
fixt.overflow?.should == true
|
154
|
+
fixt.underflow?.should == false
|
155
|
+
end
|
156
|
+
|
157
|
+
it "Forced Overflow Large overflow" do
|
158
|
+
format = FixedPoint::Format.new(1, 12, 4)
|
159
|
+
fixt = FixedPoint::Number.new(2**17, format, ".")
|
160
|
+
|
161
|
+
fixt.source.should == 2**17
|
162
|
+
|
163
|
+
max_fractional_value = (1.0/2) + (1.0/4) + (1.0/8) + (1.0/16)
|
164
|
+
|
165
|
+
fixt.to_f.should == 2**11 -1 + max_fractional_value
|
166
|
+
fixt.to_i.should == 2**11 -1
|
167
|
+
fixt.frac.should == max_fractional_value
|
168
|
+
fixt.to_h.should == "7fff"
|
169
|
+
fixt.to_b.should == "011111111111.1111"
|
170
|
+
fixt.overflow?.should == true
|
171
|
+
fixt.underflow?.should == false
|
172
|
+
end
|
173
|
+
|
174
|
+
##############################################
|
175
|
+
### Underflow Section
|
176
|
+
##############################################
|
177
|
+
#Max Negative value
|
178
|
+
it "Forced Overflow Zero fractional bits " do
|
179
|
+
format = FixedPoint::Format.new(1, 12, 0)
|
180
|
+
fixt = FixedPoint::Number.new(-2**11, format, "_")
|
181
|
+
|
182
|
+
fixt.source.should == -2**11
|
183
|
+
fixt.to_f.should == -2**11
|
184
|
+
fixt.to_i.should == -2**11
|
185
|
+
fixt.frac.should == 0.0
|
186
|
+
fixt.to_h.should == "800"
|
187
|
+
fixt.to_b.should == "100000000000"
|
188
|
+
fixt.overflow?.should == false
|
189
|
+
fixt.underflow?.should == false
|
190
|
+
end
|
191
|
+
|
192
|
+
it "Forced Overflow Zero fractional bits " do
|
193
|
+
format = FixedPoint::Format.new(1, 12, 0)
|
194
|
+
fixt = FixedPoint::Number.new(-2**11-1, format,"_")
|
195
|
+
|
196
|
+
fixt.source.should == -2**11-1
|
197
|
+
fixt.to_f.should == -2**11
|
198
|
+
fixt.to_i.should == -2**11
|
199
|
+
fixt.frac.should == 0.0
|
200
|
+
fixt.to_h.should == "800"
|
201
|
+
fixt.to_b.should == "100000000000"
|
202
|
+
fixt.overflow?.should == false
|
203
|
+
fixt.underflow?.should == true
|
204
|
+
end
|
205
|
+
|
206
|
+
it "Forced Overflow 4 fractional bits " do
|
207
|
+
format = FixedPoint::Format.new(1, 12, 4)
|
208
|
+
fixt = FixedPoint::Number.new(-2**11-1, format, ".")
|
209
|
+
|
210
|
+
fixt.source.should == -2**11-1
|
211
|
+
fixt.to_f.should == -2**11
|
212
|
+
fixt.to_i.should == -2**11
|
213
|
+
fixt.frac.should == 0.0
|
214
|
+
fixt.to_h.should == "8000"
|
215
|
+
fixt.to_b.should == "100000000000.0000"
|
216
|
+
fixt.overflow?.should == false
|
217
|
+
fixt.underflow?.should == true
|
218
|
+
end
|
219
|
+
|
220
|
+
it "Forced Overflow Large overflow" do
|
221
|
+
format = FixedPoint::Format.new(1, 12, 4)
|
222
|
+
fixt = FixedPoint::Number.new(-2**17, format, ".")
|
223
|
+
|
224
|
+
|
225
|
+
fixt.source.should == -2**17
|
226
|
+
fixt.to_f.should == -2**11
|
227
|
+
fixt.to_i.should == -2**11
|
228
|
+
fixt.frac.should == 0.0
|
229
|
+
fixt.to_h.should == "8000"
|
230
|
+
fixt.to_b.should == "100000000000.0000"
|
231
|
+
fixt.overflow?.should == false
|
232
|
+
fixt.underflow?.should == true
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
it "Creating via binary form 011_01" do
|
237
|
+
fixt = FixedPoint::Number.new(0)
|
238
|
+
|
239
|
+
fixt.binary = "011_01"
|
240
|
+
fixt.source.should == 3.25
|
241
|
+
fixt.to_f.should == 3.25
|
242
|
+
fixt.to_i.should == 3
|
243
|
+
fixt.frac.should == 0.25
|
244
|
+
fixt.to_h.should == "0d"
|
245
|
+
fixt.to_b.should == "011_01"
|
246
|
+
fixt.overflow?.should == false
|
247
|
+
fixt.underflow?.should == false
|
248
|
+
end
|
249
|
+
|
250
|
+
it "Creating via binary form 0_1" do
|
251
|
+
fixt = FixedPoint::Number.new(0)
|
252
|
+
|
253
|
+
fixt.binary = "0_1"
|
254
|
+
fixt.source.should == 0.5
|
255
|
+
fixt.to_f.should == 0.5
|
256
|
+
fixt.to_i.should == 0
|
257
|
+
fixt.frac.should == 0.5
|
258
|
+
fixt.to_h.should == "1"
|
259
|
+
fixt.to_b.should == "0_1"
|
260
|
+
fixt.overflow?.should == false
|
261
|
+
fixt.underflow?.should == false
|
262
|
+
end
|
263
|
+
|
264
|
+
it "Creating Signed via binary form 1000_1" do
|
265
|
+
fixt = FixedPoint::Number.new(0)
|
266
|
+
|
267
|
+
fixt.binary = "1000_1"
|
268
|
+
fixt.source.should == -7.5
|
269
|
+
fixt.to_f.should == -7.5
|
270
|
+
fixt.to_i.should == -7
|
271
|
+
fixt.frac.should == -0.5
|
272
|
+
fixt.to_h.should == "11"
|
273
|
+
fixt.to_b.should == "1000_1"
|
274
|
+
fixt.overflow?.should == false
|
275
|
+
fixt.underflow?.should == false
|
276
|
+
end
|
277
|
+
|
278
|
+
it "Creating Unsigned via binary form 1000_1" do
|
279
|
+
format = FixedPoint::Format.new(0, 12, 20)
|
280
|
+
fixt = FixedPoint::Number.new(0,format)
|
281
|
+
|
282
|
+
fixt.binary = "1000_1"
|
283
|
+
fixt.source.should == 8.5
|
284
|
+
fixt.to_f.should == 8.5
|
285
|
+
fixt.to_i.should == 8
|
286
|
+
fixt.frac.should == 0.5
|
287
|
+
fixt.to_h.should == "11"
|
288
|
+
fixt.to_b.should == "1000_1"
|
289
|
+
fixt.overflow?.should == false
|
290
|
+
fixt.underflow?.should == false
|
291
|
+
end
|
292
|
+
|
293
|
+
it "Creating Unsigned binary form 1000_1 using Fixdt datatype" do
|
294
|
+
format = FixedPoint::Fixdt.new(0, 32, 20) #Signed,width,frac_bits
|
295
|
+
fixt = FixedPoint::Number.new(0,format)
|
296
|
+
|
297
|
+
fixt.binary = "1000_1"
|
298
|
+
fixt.source.should == 8.5
|
299
|
+
fixt.to_f.should == 8.5
|
300
|
+
fixt.to_i.should == 8
|
301
|
+
fixt.frac.should == 0.5
|
302
|
+
fixt.to_h.should == "11"
|
303
|
+
fixt.to_b.should == "1000_1"
|
304
|
+
fixt.overflow?.should == false
|
305
|
+
fixt.underflow?.should == false
|
306
|
+
end
|
307
|
+
|
308
|
+
#need overflow test
|
309
|
+
#need underflow test
|
310
|
+
#Integer only binary test
|
311
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fixed_point
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Morgan Prior
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-01-21 00:00:00 +00:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Fixed Point numerical type for simulating fixed point calculations
|
23
|
+
email: fixed_point_gem@amaras-tech.co.uk
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- LICENSE
|
32
|
+
- README.md
|
33
|
+
- HISTORY.md
|
34
|
+
- Rakefile
|
35
|
+
- lib/fixed_point/fixdt.rb
|
36
|
+
- lib/fixed_point/format.rb
|
37
|
+
- lib/fixed_point/number.rb
|
38
|
+
- lib/fixed_point.rb
|
39
|
+
- spec/fixed_point_negative_spec.rb
|
40
|
+
- spec/fixed_point_spec.rb
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://amaras-tech.co.uk/software/fixed_point
|
44
|
+
licenses: []
|
45
|
+
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
hash: 3
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.6.2
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Fixed Point numerical type
|
76
|
+
test_files: []
|
77
|
+
|