Skip to content
Astera Technology

Why did an imported proportion become 25 instead of 0.25?

Keep the typed numeric cell value separate from its percentage display.

Download complete case notes and answer keys ↓

Read the source and its declared rule

The original extraction rule takes a numeric cell with declared percentage style as its underlying proportion. Value 0.25 may display 25%, but must remain 0.25. A separately declared text percentage follows its text grammar; a plain number without that representation is held.

Filled synthetic input
RecordInput JSON
Base input{"kind":"number","value":0.25,"style":"percent","display":"25%"}
Download editable CSV ↓

Compare the actual paths

Parsing display 25% yields 25 and changes the scale. The corrected numeric path retains 0.25; text 25% explicitly converts 25÷100.

Misleading and corrected outputs
PathOutput JSON
Misleading path{"accepted":true,"proportion":25}
Corrected path{"accepted":true,"proportion":0.25}
Download editable CSV ↓
Local Node.js program: 22.23.3 or 24.14.1
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};

import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
    if(!corrected)return {accepted:true,proportion:parseFloat(i.display)};
    if(i.kind==='number'&&i.style==='percent')return {accepted:true,proportion:i.value};
    if(i.kind==='text'&&/^\d+(?:\.\d+)?%$/.test(i.value))return {accepted:true,proportion:Number(i.value.slice(0,-1))/100};
    return {accepted:false,error:'percentage-representation-not-declared'};
  };
const cases=[{"label":"misleading base","input":{"kind":"number","value":0.25,"style":"percent","display":"25%"},"expected":{"accepted":true,"proportion":25},"corrected":false},{"label":"corrected base","input":{"kind":"number","value":0.25,"style":"percent","display":"25%"},"expected":{"accepted":true,"proportion":0.25},"corrected":true},{"label":"declared percentage text","input":{"kind":"text","value":"25%","style":null,"display":"25%"},"expected":{"accepted":true,"proportion":0.25},"corrected":true},{"label":"number without declared percentage style","input":{"kind":"number","value":25,"style":null,"display":"25"},"expected":{"accepted":false,"error":"percentage-representation-not-declared"},"corrected":true}];
for(const test of cases){
  const actual=run(test.input,test.corrected);
  assert.deepEqual(actual,test.expected,test.label);
  console.log(test.label,actual);
}
Download runnable example ↓

Check boundaries before the next load

Declared text 25% yields 0.25. Plain numeric 25 without percentage style is not guessed to be a proportion.

Editable boundary records and expected outputs
CaseInput JSONExpected output JSON
Declared text percentage{"kind":"text","value":"25%","style":null,"display":"25%"}{"accepted":true,"proportion":0.25}
No percentage representation{"kind":"number","value":25,"style":null,"display":"25"}{"accepted":false,"error":"percentage-representation-not-declared"}
Download editable CSV ↓

Which value belongs in the canonical proportion field?

Show the worked answer

0.25. The display 25% describes that proportion and is not a replacement numeric value 25.

Related resources