diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..0f6c1ba --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,34 @@ +DESIGN +====== + +Below is a list of design decisions. The justification is to be consulted +whenever a change is considered, to avoid regressions. + +### Data type for DB storage of numeric values (`decimal` vs `float`) + +* among database engines supported (by Rails), SQLite offers storage of + `decimal` data type with the lowest precision, equal to the precision of + `REAL` type (double precision float value, IEEE 754), but in a floating point + format, + * decimal types in other database engines offer greater precision, but store + data in a fixed point format, +* biology-related values differ by several orders of magnitude; storing them in + fixed point format would only make sense if required precision would be + greater than that offered by floating point format, + * even then, fixed point would mean either bigger memory requirements or + worse precision for numbers close to scale limit, + * for a fixed point format to use the same 8 bytes of storage as IEEE + 754, precision would need to be limited to 18 digits (4 bytes/9 digits) + and scale approximately half of that - 9, + * double precision floating point guarantees 15 digits of precision, which + is more than enough for all expected use cases, + * single precision floating point only guarntees 6 digits of precision, + which is estimated to be too low for some use cases (e.g. storing + latitude/longitude with a resolution grater than 100m) +* double precision floating point (IEEE 754) is a standard that ensures + compatibility with all database engines, + * the same data format is used internally by Ruby as a `Float`; it + guarantees no conversions between storage and computation, + * as a standard with hardware implementations ensures both: computing + efficiency and hardware/3rd party library compatibility as opposed to Ruby + custom `BigDecimal` type diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index ce658e3..e8c3eaf 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -102,13 +102,17 @@ module ApplicationHelper def number_field(method, options = {}) attr_type = object.type_for_attribute(method) - if attr_type.type == :decimal + case attr_type.type + when :decimal options[:value] = object.public_send(method)&.to_scientific options[:step] ||= BigDecimal(10).power(-attr_type.scale) options[:max] ||= BigDecimal(10).power(attr_type.precision - attr_type.scale) - options[:step] options[:min] = options[:min] == :step ? options[:step] : options[:min] options[:min] ||= -options[:max] + options[:size] ||= attr_type.precision / 2 + when :float + options[:size] ||= 6 end super end diff --git a/app/views/readouts/_form.html.erb b/app/views/readouts/_form.html.erb index d769a23..4b930cc 100644 --- a/app/views/readouts/_form.html.erb +++ b/app/views/readouts/_form.html.erb @@ -11,9 +11,7 @@ <%= readout.quantity.relative_pathname(@superquantity) %>