Skip to content

Commit a59a762

Browse files
committed
Merge pull request #2 from tonyhffong/master
autoscale, suffix format options
2 parents 08d46bc + 45e4af2 commit a59a762

File tree

3 files changed

+99
-7
lines changed

3 files changed

+99
-7
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,5 +198,10 @@ The keyword arguments are (Bold keywards are not printf standard)
198198
* **fractionsep**. Default `/`
199199
* **fractionwidth**. Integer. Try to pad zeros to the numerator until the fractional part has this width
200200
* **tryden**. Integer. Try to use this denominator instead of a smaller one. No-op if it'd lose precision.
201+
* **suffix**. String. This strings will be appended to the output. Useful for units/%
202+
* **autoscale**. Symbol, default `:none`. It could be `:metric`, `:binary`, or `:finance`.
203+
* `:metric` implements common SI symbols for large and small numbers e.g. `M`, `k`, `μ`, `n`
204+
* `:binary` implements common ISQ symbols for large numbers e.g. `Ti`, `Gi`, `Mi`, `Ki`
205+
* `:finance` implements common finance/news symbols for large numbers e.g. `b` (billion), `m` (millions)
201206

202207
See the test script for more examples.

src/cformat.jl

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ end
9898

9999
function generate_format_string(;
100100
width=nothing,
101-
precision=nothing,
101+
precision= -1,
102102
leftjustified=false,
103103
zeropadding=false,
104104
commas=false,
@@ -131,32 +131,35 @@ function generate_format_string(;
131131
s *= string( width )
132132
end
133133
end
134-
if precision != nothing
134+
if precision != -1
135135
s *= "." * string( precision )
136136
end
137137
s * conversion
138138
end
139139

140140
function format{T<:Real}( x::T;
141141
width=nothing,
142-
precision=nothing,
142+
precision= -1,
143143
leftjustified::Bool=false,
144144
zeropadding::Bool=false, # when right-justified, use 0 instead of space to fill
145145
commas::Bool=false,
146-
signed::Bool=false,
146+
signed::Bool=false, # +/- prefix
147147
positivespace::Bool=false,
148-
stripzeros::Bool=(precision==nothing),
148+
stripzeros::Bool=(precision== -1),
149149
parens::Bool=false, # use (1.00) instead of -1.00. Used in finance
150150
alternative::Bool=false, # usually for hex
151151
mixedfraction::Bool=false,
152152
mixedfractionsep="_",
153153
fractionsep="/", # num / den
154154
fractionwidth::Int = 0,
155155
tryden = 0, # if 2 or higher, try to use this denominator, without losing precision
156-
conversion::ASCIIString="")
156+
suffix="", # useful for units/%
157+
autoscale=:none, # :metric, :binary or :finance
158+
conversion::ASCIIString=""
159+
)
157160
checkwidth = commas
158161
if conversion == ""
159-
if T <: FloatingPoint || T <: Rational && precision != nothing
162+
if T <: FloatingPoint || T <: Rational && precision != -1
160163
actualconv = "f"
161164
elseif T <: Unsigned
162165
actualconv = "x"
@@ -175,6 +178,68 @@ function format{T<:Real}( x::T;
175178
if T <: Rational && conversion == "s"
176179
stripzeros = false
177180
end
181+
if ( T <: FloatingPoint && actualconv == "f" || T <: Integer ) && autoscale != :none
182+
actualconv = "f"
183+
if autoscale == :metric
184+
scales = [
185+
(1e24, "Y" ),
186+
(1e21, "Z" ),
187+
(1e18, "E" ),
188+
(1e15, "P" ),
189+
(1e12, "T" ),
190+
(1e9, "G"),
191+
(1e6, "M"),
192+
(1e3, "k") ]
193+
if abs(x) > 1
194+
for (mag, sym) in scales
195+
if abs(x) >= mag
196+
x /= mag
197+
suffix = sym * suffix
198+
break
199+
end
200+
end
201+
elseif T <: FloatingPoint
202+
smallscales = [
203+
( 1e-12, "p" ),
204+
( 1e-9, "n" ),
205+
( 1e-6, "μ" ),
206+
( 1e-3, "m" ) ]
207+
for (mag,sym) in smallscales
208+
if abs(x) < mag*10
209+
x /= mag
210+
suffix = sym * suffix
211+
break
212+
end
213+
end
214+
end
215+
else
216+
if autoscale == :binary
217+
scales = [
218+
(1024.0 ^8, "Yi" ),
219+
(1024.0 ^7, "Zi" ),
220+
(1024.0 ^6, "Ei" ),
221+
(1024^5, "Pi" ),
222+
(1024^4, "Ti" ),
223+
(1024^3, "Gi"),
224+
(1024^2, "Mi"),
225+
(1024, "Ki")
226+
]
227+
else # :finance
228+
scales = [
229+
(1e12, "t" ),
230+
(1e9, "b"),
231+
(1e6, "m"),
232+
(1e3, "k") ]
233+
end
234+
for (mag, sym) in scales
235+
if abs(x) >= mag
236+
x /= mag
237+
suffix = sym * suffix
238+
break
239+
end
240+
end
241+
end
242+
end
178243

179244
nonneg = x >= 0
180245
fractional = 0
@@ -264,6 +329,8 @@ function format{T<:Real}( x::T;
264329
end
265330
end
266331

332+
s *= suffix
333+
267334
if parens && !in( actualconv[1], "xX" )
268335
# if zero or positive, we still need 1 white space on the right
269336
if nonneg

test/cformat.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,26 @@ function test_format()
156156
# same with unspecified width
157157
@test format( 12345678, commas=true, parens=true )== " 12,345,678 "
158158
@test format( -12345678, commas=true, parens=true )== "(12,345,678)"
159+
160+
@test format( 1.2e9, autoscale = :metric ) == "1.2G"
161+
@test format( 1.2e6, autoscale = :metric ) == "1.2M"
162+
@test format( 1.2e3, autoscale = :metric ) == "1.2k"
163+
@test format( 1.2e-6, autoscale = :metric ) == "1.2μ"
164+
@test format( 1.2e-9, autoscale = :metric ) == "1.2n"
165+
@test format( 1.2e-12, autoscale = :metric ) == "1.2p"
166+
167+
@test format( 1.2e9, autoscale = :finance ) == "1.2b"
168+
@test format( 1.2e6, autoscale = :finance ) == "1.2m"
169+
@test format( 1.2e3, autoscale = :finance ) == "1.2k"
170+
171+
@test format( 0x40000000, autoscale = :binary ) == "1Gi"
172+
@test format( 0x100000, autoscale = :binary ) == "1Mi"
173+
@test format( 0x800, autoscale = :binary ) == "2Ki"
174+
@test format( 0x400, autoscale = :binary ) == "1Ki"
175+
176+
@test format( 100.00, precision=2, suffix="%" ) == "100.00%"
177+
@test format( 100, precision=2, suffix="%" ) == "100%"
178+
@test format( 100, precision=2, suffix="%", conversion="f" ) == "100.00%"
159179
end
160180

161181
test_commas()

0 commit comments

Comments
 (0)