Just wanted to expand on the type tolerances idea with an example: let a:Float±0.1 = 1234.56 let b:Float±0.5 = 123.456
let result:Float±0.25 = a + b // Error as b’s tolerance > 0.25 Of course this still requires developers to actually specify the tolerances at some point, however Swift’s type inference could allow them to be passed down. For example, if I omitted the type for result, then Swift could infer it as Float±0.5 as that is the higher tolerance of the two values. A plain definition of Float would be equivalent Float±infinity. This would also make the proposed tilde operator even more useful as it could be used to ignore exceptions to the tolerance, so I could change my last line to: let result:Float±0.25 = a + ~b This allows me to use the value of b (albeit with potential error higher than I’d like), without changing the tolerance of result for later operations. Also, once we have a full accuracy decimal type, I wonder if perhaps we should make it the default on the grounds of safety? While it might be overkill for many programs, I think that those programs that would see a performance impact would be too burdened by having to specify “unsafe” floating point by setting the Double or Float type (with or without a tolerance). > On 19 Mar 2016, at 00:15, Haravikk via swift-evolution > <swift-evolution@swift.org> wrote: > > I agree with all of this; I don’t really know enough to comment on the > specific implementation of a decimal type, but we definitely need something > other than NSDecimal. > > I don’t know if it’s possible, but I think that tolerances should be able to > take a percentage. For example, I could write 0.0000001±1%, which would be > much clearer (and less error prone) than 0.0000001± 0.000000001 > > This is also useful because I think we could also benefit from the addition > of tolerances to types, allowing us to declare something like: var > foo:Float±0.01 = 0, which specifies a floating point value that the Swift > compiler will not allow values to be added/substracted etc. to/from if they > have a tolerance higher than my requirement. While cumulative error could > still result in issues, if my tolerance is set reasonably low for my use-case > then it would allow me to limit how much error I can accumulate in the > lifetime of my data. In this being able to specify a percentage is useful > when the variable has a clear right hand side such as var foo:Float±5% = 0.1 > (effectively var foo:Float±0.005 = 0.1). > >> On 18 Mar 2016, at 22:42, Rainer Brockerhoff via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >> >> First draft towards a tentative pre-proposal: >> https://gist.github.com/rbrockerhoff/6874a5698bb479886e83 >> <https://gist.github.com/rbrockerhoff/6874a5698bb479886e83> >> ------ >> >> Pre-proposal: Safer Decimal Calculations >> Proposal: TBD >> Author(s): Rainer Brockerhoff >> Status: TBD >> Review manager: TBD >> >> Quoting the “The Swift Programming Language” book: “Swift adopts safe >> programming patterns…”; “Swift is friendly to new programmers”. The >> words “safe” and “safety” are found many times in the book and in online >> documentation. The usual rationale for safe features is, to quote a >> typical sentence, “…enables you to catch and fix errors as early as >> possible in the development process”. >> >> One frequent stumbling point for both new and experienced programmers >> stems from the vagaries of binary floating-point arithmetic. This >> tentative pre-proposal suggests one possible way to make the dangers >> somewhat more clear. >> >> My intention here is to start a discussion on this to inform the ongoing >> (and future) reasoning on extending and regularising arithmetic in Swift. >> >> Motivation >> >> Floating-point hardware on most platforms that run Swift — that is, >> Intel and ARM CPUs — uses the binary representation forms of the IEEE >> 754-2008 standard. Although some few mainframes and software libraries >> implement the decimal representations this is not currently leveraged by >> Swift. Apple's NSDecimal and NSDecimalNumber implementation is awkward >> to use in Swift, especially as standard arithmetic operators cannot be >> used directly. >> >> Although it is possible to express floating-point constants in >> hexadecimal (0x123.AB) with an optional binary exponent (0x123A.Bp-4), >> decimal-form floating-point constants (123.45 or 1.2345e2) are extremely >> common in practice. >> >> Unfortunately it is tempting to use floating-point arithmetic for >> financial calculations or other purposes such as labelling graphical or >> statistical data. Constants such as 0.1, 0.01, 0.001 and variations or >> multiples thereof will certainly be used in such applications — and >> almost none of these constant can be precisely represented in binary >> floating-point format. >> >> Rounding errors will therefore be introduced at the outset, causing >> unexpected or outright buggy behaviour down the line which will be >> surprising to the user and/or the programmer. This will often happen at >> some point when the results of a calculation are compared to a constant >> or to another result. >> >> Current Solution >> >> As things stand, Swift's default print() function, Xcode playgrounds >> etc. do some discreet rounding or truncation to make the problem less >> apparent - a Double initialized with the literal 0.1 prints out as 0.1 >> instead of the exact value of the internal representation, something >> like 0.100000000000000005551115123125782702118158340454101562. >> >> This, unfortunately, masks this underlying problem in settings such as >> “toy” programs or educational playgrounds, leading programmers to be >> surprised later when things won't work. A cursory search on >> StackOverflow reveals tens of thousands of questions with headings like >> “Is floating point math broken?". >> >> Warning on imprecise literals >> >> To make decimal-format floating-point literals safe, I suggest that the >> compiler should emit a warning whenever a literal is used that cannot be >> safely represented as an exact value of the type expected. (Note that >> 0.1 cannot be represented exactly as any binary floating-point type.) >> >> The experienced programmer will, however, be willing to accept some >> imprecision under circumstances that cannot be reliably determined by >> the compiler. I suggest, therefore, that this acceptance be indicated by >> an annotation to the literal; a form such as ~0.1 might be easiest to >> read and implement, as the prefix ~ operator currently has no meaning >> for a floating-point value. A “fixit” would be easily implemented to >> insert the missing notation. >> >> Conversely, to avoid inexperienced or hurried programmers to strew ~s >> everywhere, it would be useful to warn, and offer to fix, if the ~ is >> present but the literal does have an exact representation. >> >> Tolerances >> >> A parallel idea is that of tolerances, introducing an ‘epsilon’ value to >> be used in comparisons. Unfortunately an effective value of the epsilon >> depends on the magnitude of the operands and there are many edge cases. >> >> Introducing a special type along the lines of “floating point with >> tolerances” — using some accepted engineering notation for literals like >> 100.5±0.1 — might be useful for specialised applications but will not >> solve this specific problem. Expanding existing constructs to accept an >> optional tolerance value, as has been proposed elsewhere, may be useful >> in those specific instances but not contribute to raise programmer >> awareness of unsafe literals. >> >> Full Decimal type proposal >> >> There are cogent arguments that prior art/habits and the already complex >> interactions between Double, Float, Float80 and CGFloat are best left alone. >> >> However, there remains a need for a precise implementation of a workable >> Decimal value type for financial calculations. IMHO repurposing the >> existing NSDecimalNumber from Objective-C is not the best solution. >> >> As most experienced developers know, the standard solution for financial >> calculations is to internally store fixed-point values — usually but not >> always in cents — and then print the “virtual” point (or decimal comma, >> for the rest of us) on output. >> >> I propose, therefore, an internal data layout like this: >> >> UInt16 - position of the “virtual” point, starting at 0 >> UInt16 - data array size - 1 >> [Int32] - contiguous data array, little-endian order, grown as needed. >> Note that both UInt16 fields being zero implies that the number is >> reduced to a 32-bit Integer. Number literals in Swift can be up to 2048 >> bits in size, so the maximum data array size would be 64, although it >> could conceivably grow beyond that. The usual cases of the virtual point >> position being 0 or 2 could be aggressively optimized for normal >> arithmetic operators. >> >> Needless to say such a Decimal number would accept and represent >> literals such as 0.01 with no problems. It would also serve as a BigNum >> implementation for most purposes. >> >> No doubt implementing this type in the standard library would allow for >> highly optimized implementations for all major CPU platforms. In >> particular, the data array should probably be [Int64] for 64-bit platforms. >> >> Acknowledgement >> >> Thanks to Erica Sadun for their help with an early version of this >> pre-proposal. >> >> Some references >> >> http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html >> https://docs.python.org/2/tutorial/floatingpoint.html >> https://en.wikipedia.org/wiki/IEEE_floating_point >> https://randomascii.wordpress.com/category/floating-point/ >> http://code.jsoftware.com/wiki/Essays/Tolerant_Comparison >> >> -- >> Rainer Brockerhoff <rai...@brockerhoff.net> >> Belo Horizonte, Brazil >> "In the affairs of others even fools are wise >> In their own business even sages err." >> http://brockerhoff.net/blog/ >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org >> https://lists.swift.org/mailman/listinfo/swift-evolution > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution