more shiller optimizations
This commit is contained in:
parent
68392efec4
commit
a129d5a372
1 changed files with 3 additions and 114 deletions
|
|
@ -97,7 +97,7 @@ fn parseShillerData() []const ShillerYear {
|
|||
// Fast reject: date is "YYYY.01,"
|
||||
if (line[4] != '.' or line[5] != '0' or line[6] != '1') continue;
|
||||
|
||||
const year = parseU16(line[0..4]) orelse continue;
|
||||
const year = std.fmt.parseInt(u16, line[0..4], 10) catch continue;
|
||||
|
||||
// Parse fields for this January row
|
||||
var col_iter = CsvFieldIterator{ .data = line };
|
||||
|
|
@ -112,8 +112,8 @@ fn parseShillerData() []const ShillerYear {
|
|||
_ = col_iter.next(); // col 8
|
||||
const tr_price_field = col_iter.next() orelse continue;
|
||||
|
||||
const cpi = parseF64(stripSpaces(cpi_field)) orelse continue;
|
||||
const gs10 = parseF64(stripSpaces(gs10_field)) orelse continue;
|
||||
const cpi = parseF64WithCommas(cpi_field) orelse continue;
|
||||
const gs10 = parseF64WithCommas(gs10_field) orelse continue;
|
||||
const tr_price = parseF64WithCommas(tr_price_field) orelse continue;
|
||||
|
||||
if (cpi == 0.0 or tr_price == 0.0 or gs10 == 0.0) continue;
|
||||
|
|
@ -144,60 +144,6 @@ fn parseShillerData() []const ShillerYear {
|
|||
if (pos < csv_data.len) pos += 1;
|
||||
}
|
||||
|
||||
// Single pass: scan lines, parse January rows, compute returns on the fly.
|
||||
while (pos < csv_data.len) {
|
||||
const line_start = pos;
|
||||
while (pos < csv_data.len and csv_data[pos] != '\n') pos += 1;
|
||||
const line_end = if (pos > line_start and csv_data[pos - 1] == '\r') pos - 1 else pos;
|
||||
if (pos < csv_data.len) pos += 1;
|
||||
|
||||
const line = csv_data[line_start..line_end];
|
||||
if (line.len < 7) continue;
|
||||
|
||||
// Fast reject: date is "YYYY.01," — check fixed offsets
|
||||
if (line[4] != '.' or line[5] != '0' or line[6] != '1') continue;
|
||||
|
||||
const year = parseU16(line[0..4]) orelse continue;
|
||||
|
||||
// Parse fields for this January row
|
||||
var col_iter = CsvFieldIterator{ .data = line };
|
||||
_ = col_iter.next(); // col 0: Date
|
||||
_ = col_iter.next(); // col 1: P
|
||||
_ = col_iter.next(); // col 2: D
|
||||
_ = col_iter.next(); // col 3: E
|
||||
const cpi_field = col_iter.next() orelse continue;
|
||||
_ = col_iter.next(); // col 5
|
||||
const gs10_field = col_iter.next() orelse continue;
|
||||
_ = col_iter.next(); // col 7
|
||||
_ = col_iter.next(); // col 8
|
||||
const tr_price_field = col_iter.next() orelse continue;
|
||||
|
||||
const cpi = parseF64(stripSpaces(cpi_field)) orelse continue;
|
||||
const gs10 = parseF64(stripSpaces(gs10_field)) orelse continue;
|
||||
const tr_price = parseF64WithCommas(tr_price_field) orelse continue;
|
||||
|
||||
if (cpi == 0.0 or tr_price == 0.0 or gs10 == 0.0) continue;
|
||||
|
||||
// Compute return from previous January (if consecutive)
|
||||
if (prev_year > 0 and year == prev_year + 1) {
|
||||
const cpi_change = (cpi / prev_cpi) - 1.0;
|
||||
const real_sp500 = (tr_price / prev_tr_price) - 1.0;
|
||||
|
||||
results[result_count] = .{
|
||||
.year = prev_year,
|
||||
.sp500_total_return = (1.0 + real_sp500) * (1.0 + cpi_change) - 1.0,
|
||||
.bond_total_return = prev_gs10 / 100.0,
|
||||
.cpi_inflation = cpi_change,
|
||||
};
|
||||
result_count += 1;
|
||||
}
|
||||
|
||||
prev_year = year;
|
||||
prev_tr_price = tr_price;
|
||||
prev_gs10 = gs10;
|
||||
prev_cpi = cpi;
|
||||
}
|
||||
|
||||
if (result_count == 0) return &.{};
|
||||
|
||||
const final = blk: {
|
||||
|
|
@ -256,63 +202,6 @@ const CsvFieldIterator = struct {
|
|||
}
|
||||
};
|
||||
|
||||
fn indexOf(s: []const u8, ch: u8) ?usize {
|
||||
for (s, 0..) |c, i| {
|
||||
if (c == ch) return i;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn parseU16(s: []const u8) ?u16 {
|
||||
if (s.len == 0) return null;
|
||||
var result: u16 = 0;
|
||||
for (s) |c| {
|
||||
if (c < '0' or c > '9') return null;
|
||||
result = result * 10 + @as(u16, c - '0');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn parseF64(s: []const u8) ?f64 {
|
||||
if (s.len == 0) return null;
|
||||
|
||||
var negative = false;
|
||||
var start: usize = 0;
|
||||
if (s[0] == '-') {
|
||||
negative = true;
|
||||
start = 1;
|
||||
}
|
||||
|
||||
var integer_part: f64 = 0;
|
||||
var i = start;
|
||||
while (i < s.len and s[i] != '.') : (i += 1) {
|
||||
if (s[i] < '0' or s[i] > '9') return null;
|
||||
integer_part = integer_part * 10.0 + @as(f64, @floatFromInt(s[i] - '0'));
|
||||
}
|
||||
|
||||
var frac_part: f64 = 0;
|
||||
if (i < s.len and s[i] == '.') {
|
||||
i += 1;
|
||||
var divisor: f64 = 10.0;
|
||||
while (i < s.len) : (i += 1) {
|
||||
if (s[i] < '0' or s[i] > '9') return null;
|
||||
frac_part += @as(f64, @floatFromInt(s[i] - '0')) / divisor;
|
||||
divisor *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
const result = integer_part + frac_part;
|
||||
return if (negative) -result else result;
|
||||
}
|
||||
|
||||
fn stripSpaces(s: []const u8) []const u8 {
|
||||
var start: usize = 0;
|
||||
var end: usize = s.len;
|
||||
while (start < end and s[start] == ' ') start += 1;
|
||||
while (end > start and s[end - 1] == ' ') end -= 1;
|
||||
return s[start..end];
|
||||
}
|
||||
|
||||
fn parseF64WithCommas(s: []const u8) ?f64 {
|
||||
if (s.len == 0) return null;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue