fixed_point 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/HISTORY.md ADDED
@@ -0,0 +1,14 @@
1
+ HISTORY/Changelog
2
+ =================
3
+
4
+ 0.1.0
5
+ -----
6
+
7
+ Improved API, to_b, to_h, to_i, to_f
8
+ Working hex output
9
+
10
+ 0.0.1
11
+ -----
12
+
13
+ Define number of integer and fractional bits with real/integer value input.
14
+
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
@@ -0,0 +1,11 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ file_list = FileList['spec/*_spec.rb']
4
+
5
+ RSpec::Core::RakeTask.new('spec') do |t|
6
+ t.pattern = file_list
7
+ t.rspec_opts = ["--colour", "--format progress"]
8
+ end
9
+
10
+ desc 'Default: run specs.'
11
+ task :default => 'spec'
@@ -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,8 @@
1
+ module FixedPoint
2
+ class Fixdt < Format
3
+ #Designed to be compatible with Matlab/Simulink types
4
+ def initialize(signed, width, frac_bits)
5
+ super( signed, width-frac_bits, frac_bits )
6
+ end
7
+ end
8
+ end #module FixedPoint
@@ -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
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
2
+
3
+ require 'rspec'
4
+ require 'fixed_point'
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
+