excel_to_code 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/src/commands/excel_to_c.rb +2 -3
- data/src/commands/excel_to_x.rb +13 -1
- data/src/compile/c/a.out +0 -0
- data/src/compile/c/excel_to_c_runtime.c +39 -0
- data/src/compile/c/excel_to_c_runtime_test.c +21 -0
- data/src/compile/c/map_formulae_to_c.rb +5 -0
- data/src/compile/ruby/map_formulae_to_ruby.rb +1 -0
- data/src/excel/excel_functions.rb +2 -0
- data/src/excel/excel_functions/npv.rb +20 -0
- data/src/excel_to_code.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a337c16718282fa8bbce1da4a51cb81d2ad6651
|
4
|
+
data.tar.gz: fbfa6de417b5b4f8fe626244b234876cd00f430c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf150004e0ad6ad4cf8d17d4abc740c4b5e33e3224c39091a2d9b9edc65d4e66de2ba047446c9cbc04fe7c33f680ed156300dc10ca568f38e7c6e97a70896a7e
|
7
|
+
data.tar.gz: 28bbe1191e5da2bbcbc63d4bda866f6f1720c619212659d6aeaece6c9e21baa7597b95ec7e6d77718895ff9bed54f9cc07c4cd5674a8918fb73874ebfbd12044
|
data/README.md
CHANGED
@@ -48,3 +48,4 @@ There are some how to guides in the doc folder.
|
|
48
48
|
7. Newlines are removed from strings
|
49
49
|
8. The generated code uses floating point, rather than fully precise arithmetic, so results can differ slightly
|
50
50
|
9. The generated code uses the sprintf approach to rounding (even-odd) rather than excel's 0.5 rounds away from zero.
|
51
|
+
10. Ranges like this: Sheet1!A10:Sheet1!B20 and 3D ranges don't work
|
data/src/commands/excel_to_c.rb
CHANGED
@@ -380,9 +380,8 @@ END
|
|
380
380
|
return unless actually_compile_code || actually_run_tests
|
381
381
|
name = output_name.downcase
|
382
382
|
log.info "Compiling"
|
383
|
-
puts `
|
384
|
-
puts `gcc -fPIC -o #{name}
|
385
|
-
puts `gcc -shared -fPIC -o #{FFI.map_library_name(name)} #{name}.o`
|
383
|
+
puts `gcc -fPIC -o #{File.join(output_directory, name)}.o -c #{File.join(output_directory, name)}.c`
|
384
|
+
puts `gcc -shared -fPIC -o #{File.join(output_directory, FFI.map_library_name(name))} #{File.join(output_directory, name)}.o`
|
386
385
|
end
|
387
386
|
|
388
387
|
def run_tests
|
data/src/commands/excel_to_x.rb
CHANGED
@@ -142,6 +142,7 @@ class ExcelToX
|
|
142
142
|
# format and refer to sheets and references that actually exist
|
143
143
|
clean_cells_that_can_be_set_at_runtime
|
144
144
|
clean_cells_to_keep
|
145
|
+
convert_named_references_into_simple_form
|
145
146
|
clean_named_references_to_keep
|
146
147
|
clean_named_references_that_can_be_set_at_runtime
|
147
148
|
|
@@ -308,11 +309,22 @@ class ExcelToX
|
|
308
309
|
raise
|
309
310
|
end
|
310
311
|
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
# Named references can be simple cell references,
|
316
|
+
# or they can be ranges, or errors, or table references
|
317
|
+
# this function converts all the different types into
|
318
|
+
# arrays of cell references
|
319
|
+
def convert_named_references_into_simple_form
|
311
320
|
# Replace A$1:B2 with [A1, A2, B1, B2]
|
312
321
|
@replace_ranges_with_array_literals_replacer ||= ReplaceRangesWithArrayLiteralsAst.new
|
322
|
+
table_reference_replacer = ReplaceTableReferenceAst.new(@tables)
|
313
323
|
|
314
324
|
@named_references.each do |name, reference|
|
315
|
-
|
325
|
+
reference = table_reference_replacer.map(reference)
|
326
|
+
reference = @replace_ranges_with_array_literals_replacer.map(reference)
|
327
|
+
@named_references[name] = reference
|
316
328
|
end
|
317
329
|
|
318
330
|
end
|
data/src/compile/c/a.out
CHANGED
Binary file
|
@@ -83,6 +83,7 @@ static ExcelValue min(int number_of_arguments, ExcelValue *arguments);
|
|
83
83
|
static ExcelValue mmult(ExcelValue a_v, ExcelValue b_v);
|
84
84
|
static ExcelValue mod(ExcelValue a_v, ExcelValue b_v);
|
85
85
|
static ExcelValue negative(ExcelValue a_v);
|
86
|
+
static ExcelValue npv(ExcelValue rate, int number_of_arguments, ExcelValue *arguments);
|
86
87
|
static ExcelValue pmt(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v);
|
87
88
|
static ExcelValue power(ExcelValue a_v, ExcelValue b_v);
|
88
89
|
static ExcelValue pv_3(ExcelValue a_v, ExcelValue b_v, ExcelValue c_v);
|
@@ -1310,6 +1311,44 @@ static ExcelValue sum(int array_size, ExcelValue *array) {
|
|
1310
1311
|
return new_excel_number(total);
|
1311
1312
|
}
|
1312
1313
|
|
1314
|
+
static ExcelValue npv(ExcelValue rate_v, int number_of_arguments, ExcelValue *arguments) {
|
1315
|
+
CHECK_FOR_PASSED_ERROR(rate_v)
|
1316
|
+
NUMBER(rate_v, rate)
|
1317
|
+
CHECK_FOR_CONVERSION_ERROR
|
1318
|
+
if(rate == -1) { return DIV0; }
|
1319
|
+
|
1320
|
+
double npv = 0;
|
1321
|
+
int n = 1;
|
1322
|
+
int i;
|
1323
|
+
int j;
|
1324
|
+
double v;
|
1325
|
+
ExcelValue r;
|
1326
|
+
ExcelValue r2;
|
1327
|
+
ExcelValue *range;
|
1328
|
+
|
1329
|
+
for(i=0;i<number_of_arguments;i++) {
|
1330
|
+
r = arguments[i];
|
1331
|
+
if(r.type == ExcelError) { return r; }
|
1332
|
+
if(r.type == ExcelRange) {
|
1333
|
+
range = r.array;
|
1334
|
+
for(j=0;j<(r.columns*r.rows);j++) {
|
1335
|
+
r2 = range[j];
|
1336
|
+
if(r2.type == ExcelError) { return r2; }
|
1337
|
+
v = number_from(r2);
|
1338
|
+
if(conversion_error) { conversion_error = 0; return VALUE; }
|
1339
|
+
npv = npv + (v/pow(1+rate, n));
|
1340
|
+
n++;
|
1341
|
+
}
|
1342
|
+
} else {
|
1343
|
+
v = number_from(r);
|
1344
|
+
if(conversion_error) { conversion_error = 0; return VALUE; }
|
1345
|
+
npv = npv + (v/pow(1+rate, n));
|
1346
|
+
n++;
|
1347
|
+
}
|
1348
|
+
}
|
1349
|
+
return new_excel_number(npv);
|
1350
|
+
}
|
1351
|
+
|
1313
1352
|
static ExcelValue max(int number_of_arguments, ExcelValue *arguments) {
|
1314
1353
|
double biggest_number_found;
|
1315
1354
|
int any_number_found = 0;
|
@@ -959,6 +959,27 @@ int test_functions() {
|
|
959
959
|
assert(value(new_excel_string("1")).number == 1);
|
960
960
|
assert(value(new_excel_string("A1A")).type == ExcelError);
|
961
961
|
|
962
|
+
|
963
|
+
// NPV(rate, flow1, flow2)
|
964
|
+
ExcelValue npv_array1[] = { new_excel_number(110) };
|
965
|
+
assert(npv(new_excel_number(0.1), 1, npv_array1).type == ExcelNumber);
|
966
|
+
assert(npv(new_excel_number(0.1), 1, npv_array1).number-100 < 0.001);
|
967
|
+
|
968
|
+
ExcelValue npv_array2[] = { new_excel_number(110), new_excel_number(121) };
|
969
|
+
assert((npv(new_excel_number(0.1), 2, npv_array2).number - 200) < 0.001);
|
970
|
+
|
971
|
+
ExcelValue npv_array3[] = { new_excel_number(110), new_excel_number(121)};
|
972
|
+
ExcelValue npv_array3_v = new_excel_range(npv_array3,2,1);
|
973
|
+
ExcelValue npv_array4[] = { npv_array3_v };
|
974
|
+
|
975
|
+
assert((npv(new_excel_number(0.1), 1, npv_array4).number - 200) < 0.001);
|
976
|
+
|
977
|
+
assert(npv(new_excel_number(-1.0), 1, npv_array1).type == ExcelError);
|
978
|
+
assert(npv(BLANK, 1, npv_array1).number == 110);
|
979
|
+
|
980
|
+
ExcelValue npv_array5[] = { BLANK };
|
981
|
+
assert(npv(new_excel_number(0.1), 1, npv_array5).number == 0);
|
982
|
+
|
962
983
|
// Release memory
|
963
984
|
free_all_allocated_memory();
|
964
985
|
|
@@ -66,6 +66,7 @@ class MapFormulaeToC < MapValuesToC
|
|
66
66
|
:'MIN' => 'min',
|
67
67
|
:'MMULT' => 'mmult',
|
68
68
|
:'MOD' => 'mod',
|
69
|
+
:'NPV' => 'npv',
|
69
70
|
:'PMT' => 'pmt',
|
70
71
|
:'PV3' => 'pv_3',
|
71
72
|
:'PV4' => 'pv_4',
|
@@ -156,6 +157,10 @@ class MapFormulaeToC < MapValuesToC
|
|
156
157
|
"#{FUNCTIONS[:AVERAGEIFS]}(#{map(average_range)}, #{map_arguments_to_array(criteria)})"
|
157
158
|
end
|
158
159
|
|
160
|
+
def function_npv(rate,*cash_flows)
|
161
|
+
"#{FUNCTIONS[:NPV]}(#{map(rate)}, #{map_arguments_to_array(cash_flows)})"
|
162
|
+
end
|
163
|
+
|
159
164
|
def function_if(condition, true_case, false_case = [:boolean_false])
|
160
165
|
true_code = map(true_case)
|
161
166
|
false_code = map(false_case)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ExcelFunctions
|
2
|
+
|
3
|
+
def npv(rate, *values)
|
4
|
+
# Turn the arguments into numbers
|
5
|
+
rate = number_argument(rate)
|
6
|
+
values = values.flatten.map { |v| number_argument(v) }
|
7
|
+
|
8
|
+
# Check for errors
|
9
|
+
return rate if rate.is_a?(Symbol)
|
10
|
+
return :div0 if rate == -1
|
11
|
+
values.each { |v| return v if v.is_a?(Symbol) }
|
12
|
+
|
13
|
+
npv = 0
|
14
|
+
|
15
|
+
values.each.with_index { |v, i| npv = npv + (v/((1+rate)**(i+1))) }
|
16
|
+
|
17
|
+
npv
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/src/excel_to_code.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: excel_to_code
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Counsell, Green on Black Ltd
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubypeg
|
@@ -105,7 +105,8 @@ description: "# excel_to_code\n\nConverts some excel spreadsheets (.xlsx, not .x
|
|
105
105
|
multithread and will give bad results if you try\n7. Newlines are removed from strings\n8.
|
106
106
|
The generated code uses floating point, rather than fully precise arithmetic, so
|
107
107
|
results can differ slightly\n9. The generated code uses the sprintf approach to
|
108
|
-
rounding (even-odd) rather than excel's 0.5 rounds away from zero.\
|
108
|
+
rounding (even-odd) rather than excel's 0.5 rounds away from zero.\n10. Ranges like
|
109
|
+
this: Sheet1!A10:Sheet1!B20 and 3D ranges don't work\n"
|
109
110
|
email: tamc@greenonblack.com
|
110
111
|
executables:
|
111
112
|
- excel_to_c
|
@@ -189,6 +190,7 @@ files:
|
|
189
190
|
- src/excel/excel_functions/multiply.rb
|
190
191
|
- src/excel/excel_functions/negative.rb
|
191
192
|
- src/excel/excel_functions/not_equal.rb
|
193
|
+
- src/excel/excel_functions/npv.rb
|
192
194
|
- src/excel/excel_functions/number_argument.rb
|
193
195
|
- src/excel/excel_functions/pi.rb
|
194
196
|
- src/excel/excel_functions/pmt.rb
|