Skip to content

Commit 0414060

Browse files
authored
Merge pull request #17 from satotake/add-features
Add features
2 parents bc652c9 + 6f853dd commit 0414060

File tree

4 files changed

+135
-26
lines changed

4 files changed

+135
-26
lines changed

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,49 @@ n.toNumerals()
7575
NumeralZero { raw: 123456789, unit: 0 }
7676
]
7777
```
78+
79+
#### Numerals.round
80+
- round: : (base: JpNumeralUnit) => Numerals
81+
82+
```ts
83+
import {numerals} from 'jp-numerals';
84+
const n = numerals(12_3456_7890)
85+
86+
n.round(JpNumeralUnit.億).toString()
87+
// => returns
88+
'12億'
89+
90+
```
91+
92+
#### Signed methods
93+
94+
- sign: () => Sign
95+
- toSignedNumerals: () => [Sign, Numeral[]]
96+
- toSignedTuples: () => [Sign, [number, string][]]
97+
- toSignedNumeralObjs: () => [Sign, NumeralObj[]]
98+
- toSignedString: () => string
99+
100+
```ts
101+
import {numerals} from 'jp-numerals';
102+
const n = numerals(-123456789)
103+
104+
n.sign()
105+
// => returns -1
106+
107+
n.toSignedString()
108+
// => returns '-1億2345万6789'
109+
110+
n.toSignedNumeralObjs()
111+
// => returns
112+
[
113+
-1,
114+
[
115+
{ unit: 2, character: '', rank: 2, digits: 1 },
116+
{ unit: 1, character: '', rank: 1, digits: 2345 },
117+
{ unit: 0, character: '', rank: 0, digits: 6789 }
118+
]
119+
]
120+
```
78121
---
79122

80123
This library is based on [typescript-library-starter](https://github.com/alexjoverm/typescript-library-starter/)

__tests__/jp-numerals.ts

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,26 +86,74 @@ describe('jpNumerals', () => {
8686

8787
expect(n.toString()).toEqual('12億3456万7890')
8888
expect(n.toNumber()).toEqual(1234567890)
89+
90+
const n2 = numerals(1_0000_0000)
91+
expect(n2.toString()).toEqual('1億')
8992
})
9093

9194
it('can handle float', () => {
9295
const n = numerals(12_3456_7890.123)
9396
expect(n.toTuples()).toEqual([[12, '億'], [3456, '万'], [7890.123, '']])
9497
})
9598

96-
it('throw error if number is negative', () => {
97-
expect(() => numerals(-12_3456_7890.123)).toThrow()
99+
it('can handle negative integer', () => {
100+
const n = numerals(-12_3456_789_0)
101+
const p = numerals(+12_3456_789_0)
102+
103+
expect(n.sign()).toEqual(-1)
104+
105+
expect(n.toAbsNumber()).toEqual(12_3456_789_0)
106+
expect(n.toNumber()).toEqual(-12_3456_789_0)
107+
expect(n.toSignedString()).toEqual('-12億3456万7890')
108+
expect(p.toSignedString()).toEqual('12億3456万7890')
109+
expect(n.toSignedTuples()).toEqual([-1, [[12, '億'], [3456, '万'], [7890, '']]])
110+
expect(n.toSignedNumerals()).toEqual([-1, [
111+
new Numeral(JpNumeralUnit., 12_3456_7890),
112+
new Numeral(JpNumeralUnit., 12_3456_7890),
113+
new Numeral(JpNumeralUnit., 12_3456_7890)
114+
]])
115+
expect(n.toSignedNumeralObjs()).toEqual([-1, [
116+
{
117+
unit: JpNumeralUnit.,
118+
character: '億',
119+
rank: 2,
120+
digits: 12
121+
},
122+
{
123+
unit: JpNumeralUnit.,
124+
character: '万',
125+
rank: 1,
126+
digits: 3456
127+
},
128+
{
129+
unit: JpNumeralUnit.,
130+
character: '',
131+
rank: 0,
132+
digits: 7890
133+
}
134+
]])
98135
})
99136

100137
it('can use base as option', () => {
101-
const n_base = numerals(12_3456, JpNumeralUnit.)
138+
const nBase = numerals(12_3456, JpNumeralUnit.)
102139
const n = numerals(12_3456_0000)
103140

104-
expect(n_base.toTuples()).toEqual(n.toTuples())
105-
expect(n_base.toNumerals()).toEqual(n.toNumerals())
106-
expect(n_base.toNumeralObjs()).toEqual(n.toNumeralObjs())
141+
expect(nBase.toTuples()).toEqual(n.toTuples())
142+
expect(nBase.toNumerals()).toEqual(n.toNumerals())
143+
expect(nBase.toNumeralObjs()).toEqual(n.toNumeralObjs())
144+
145+
expect(nBase.toString()).toEqual(n.toString())
146+
expect(nBase.toNumber()).toEqual(1234560000)
147+
})
148+
149+
it('can round number with specified unit', () => {
150+
const positive = numerals(12_3456_7890)
151+
const negative = numerals(-9999_9999_9999)
152+
153+
expect(positive.round(JpNumeralUnit.).toString()).toEqual('12億3457万')
154+
expect(positive.round(JpNumeralUnit.).toString()).toEqual('12億')
107155

108-
expect(n_base.toString()).toEqual(n.toString())
109-
expect(n_base.toNumber()).toEqual(1234560000)
156+
expect(negative.round(JpNumeralUnit.).toSignedString()).toEqual('-1兆')
157+
expect(negative.round(JpNumeralUnit.).toSignedString()).toEqual('-1兆')
110158
})
111159
})

src/jp-numerals.ts

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import { JpNumeralUnit, NumeralObj, Numerals } from './type'
2-
export { JpNumeralUnit, NumeralObj, Numerals }
1+
import { JpNumeralUnit, NumeralObj, Numerals, Sign } from './type'
2+
export { JpNumeralUnit, NumeralObj, Numerals, Sign }
33

4+
const EPSILON = 1e-10
45
const log10 = (v: number) => Math.log(v) / Math.log(10)
6+
// for IE
57

68
export class Numeral {
79
raw: number
@@ -32,7 +34,7 @@ export class Numeral {
3234
return [digits, character]
3335
}
3436
toString(): string {
35-
return `${this.digits}${this.character}`
37+
return this.digits === 0 ? '' : `${this.digits}${this.character}`
3638
}
3739
toNumeralObj(): NumeralObj {
3840
const { unit, character, rank, digits } = this
@@ -59,28 +61,33 @@ export class NumeralZero extends Numeral {
5961
}
6062

6163
export const numerals = (n: number, base: JpNumeralUnit = JpNumeralUnit.): Numerals => {
62-
// TODO(handle negative)
63-
if (n < 0) {
64-
throw Error('number must be string')
65-
}
66-
67-
const raw = Math.abs(n) * Math.pow(10, base * 4)
64+
const sign = n < 0 ? -1 : 1
65+
const abs = Math.abs(n) * Math.pow(10, base * 4)
6866
// in myriads
6967

70-
const unitLen = Object.keys(JpNumeralUnit).length / 2
71-
const numberLen = Math.ceil(log10(raw) / 4)
68+
const unitLen = Object.keys(JpNumeralUnit).length / 2 // maximum unit
69+
const numberLen = Math.ceil(log10(abs) / 4 + EPSILON)
7270
const len = Math.min(unitLen, numberLen)
73-
const numerals = new Array(len)
71+
const nums = new Array(len)
7472
.fill(NaN)
75-
.map((_, i) => (i === 0 ? new NumeralZero(i, raw) : new Numeral(i, raw)))
73+
.map((_, i) => (i === 0 ? new NumeralZero(i, abs) : new Numeral(i, abs)))
7674
.reverse()
7775

7876
return {
79-
toNumerals: () => numerals,
80-
toTuples: () => numerals.map(numeral => numeral.toTuple()),
81-
toNumeralObjs: () => numerals.map(numeral => numeral.toNumeralObj()),
82-
toString: () => numerals.reduce((s, numeral) => `${s}${numeral}`, ''),
83-
toNumber: () => raw
77+
toNumerals: () => nums,
78+
toTuples: () => nums.map(numeral => numeral.toTuple()),
79+
toNumeralObjs: () => nums.map(numeral => numeral.toNumeralObj()),
80+
toString: () => nums.reduce((s, numeral) => `${s}${numeral}`, ''),
81+
toAbsNumber: () => abs,
82+
83+
sign: () => sign,
84+
toSignedNumerals: () => [sign, nums],
85+
toSignedTuples: () => [sign, nums.map(numeral => numeral.toTuple())],
86+
toSignedNumeralObjs: () => [sign, nums.map(numeral => numeral.toNumeralObj())],
87+
toSignedString: () => nums.reduce((s, numeral) => `${s}${numeral}`, sign === -1 ? '-' : ''),
88+
toNumber: () => sign * abs,
89+
90+
round: (base: JpNumeralUnit) => numerals(sign * Math.round(abs / Math.pow(10, base * 4)), base)
8491
}
8592
}
8693

src/type.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,16 @@ export interface Numerals {
3434
toTuples: () => [number, string][]
3535
toNumeralObjs: () => NumeralObj[]
3636
toString: () => string
37+
toAbsNumber: () => number
38+
39+
sign: () => Sign
40+
toSignedNumerals: () => [Sign, Numeral[]]
41+
toSignedTuples: () => [Sign, [number, string][]]
42+
toSignedNumeralObjs: () => [Sign, NumeralObj[]]
43+
toSignedString: () => string
3744
toNumber: () => number
45+
46+
round: (base: JpNumeralUnit) => Numerals
3847
}
48+
49+
export type Sign = -1 | 1

0 commit comments

Comments
 (0)