@@ -198,6 +198,42 @@ unicode_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMet
198198 return NPY_UNSAFE_CASTING;
199199}
200200
201+ // Helper function: Convert UCS4 string to quad_value
202+ static inline int
203+ unicode_to_quad_convert (const Py_UCS4 *ucs4_str, npy_intp unicode_size_chars,
204+ QuadBackendType backend, quad_value *out_val)
205+ {
206+ // Temporary buffer to convert UCS4 to null-terminated char string
207+ char temp_str[QUAD_STR_WIDTH + 1 ];
208+ npy_intp copy_len = unicode_size_chars < QUAD_STR_WIDTH ? unicode_size_chars : QUAD_STR_WIDTH;
209+
210+ // Convert UCS4 characters to ASCII/char
211+ npy_intp i;
212+ for (i = 0 ; i < copy_len; i++) {
213+ Py_UCS4 c = ucs4_str[i];
214+
215+ // reject non-ASCII characters
216+ if (c > 127 ) {
217+ PyErr_Format (PyExc_ValueError,
218+ " Cannot cast non-ASCII character '%c' to QuadPrecision" , c);
219+ return -1 ;
220+ }
221+
222+ temp_str[i] = (char )c;
223+ }
224+ temp_str[i] = ' \0 ' ;
225+
226+ char *endptr;
227+ int err = cstring_to_quad (temp_str, backend, out_val, &endptr, true );
228+ if (err < 0 ) {
229+ PyErr_Format (PyExc_ValueError,
230+ " could not convert string to QuadPrecision: np.str_('%s')" , temp_str);
231+ return -1 ;
232+ }
233+
234+ return 0 ;
235+ }
236+
201237static int
202238unicode_to_quad_strided_loop_unaligned (PyArrayMethod_Context *context, char *const data[],
203239 npy_intp const dimensions[], npy_intp const strides[],
@@ -217,33 +253,10 @@ unicode_to_quad_strided_loop_unaligned(PyArrayMethod_Context *context, char *con
217253 npy_intp unicode_size_chars = descrs[0 ]->elsize / 4 ;
218254
219255 while (N--) {
220- // Temporary buffer to convert UCS4 to null-terminated char string
221- char temp_str[QUAD_STR_WIDTH + 1 ];
222- npy_intp copy_len =
223- unicode_size_chars < QUAD_STR_WIDTH ? unicode_size_chars : QUAD_STR_WIDTH;
224- // Convert UCS4 characters to ASCII/char
225256 Py_UCS4 *ucs4_str = (Py_UCS4 *)in_ptr;
226- npy_intp i;
227- for (i = 0 ; i < copy_len; i++) {
228- Py_UCS4 c = ucs4_str[i];
229-
230- // reject non-ASCII characters
231- if (c > 127 ) {
232- PyErr_Format (PyExc_ValueError,
233- " Cannot cast non-ASCII character '%c' to QuadPrecision" , c);
234- return -1 ;
235- }
236-
237- temp_str[i] = (char )c;
238- }
239- temp_str[i] = ' \0 ' ;
240-
241257 quad_value out_val;
242- char *endptr;
243- int err = cstring_to_quad (temp_str, backend, &out_val, &endptr, true );
244- if (err < 0 ) {
245- PyErr_Format (PyExc_ValueError,
246- " could not convert string to QuadPrecision: np.str_('%s')" , temp_str);
258+
259+ if (unicode_to_quad_convert (ucs4_str, unicode_size_chars, backend, &out_val) < 0 ) {
247260 return -1 ;
248261 }
249262
@@ -280,33 +293,10 @@ unicode_to_quad_strided_loop_aligned(PyArrayMethod_Context *context, char *const
280293 npy_intp unicode_size_chars = descrs[0 ]->elsize / 4 ;
281294
282295 while (N--) {
283- // Temporary buffer to convert UCS4 to null-terminated char string
284- char temp_str[QUAD_STR_WIDTH + 1 ];
285- npy_intp copy_len =
286- unicode_size_chars < QUAD_STR_WIDTH ? unicode_size_chars : QUAD_STR_WIDTH;
287- // Convert UCS4 characters to ASCII/char
288296 Py_UCS4 *ucs4_str = (Py_UCS4 *)in_ptr;
289- npy_intp i;
290- for (i = 0 ; i < copy_len; i++) {
291- Py_UCS4 c = ucs4_str[i];
292-
293- // reject non-ASCII characters
294- if (c > 127 ) {
295- PyErr_Format (PyExc_ValueError,
296- " Cannot cast non-ASCII character '%c' to QuadPrecision" , c);
297- return -1 ;
298- }
299-
300- temp_str[i] = (char )c;
301- }
302- temp_str[i] = ' \0 ' ;
303-
304297 quad_value out_val;
305- char *endptr;
306- int err = cstring_to_quad (temp_str, backend, &out_val, &endptr, true );
307- if (err < 0 ) {
308- PyErr_Format (PyExc_ValueError,
309- " could not convert string to QuadPrecision: np.str_('%s')" , temp_str);
298+
299+ if (unicode_to_quad_convert (ucs4_str, unicode_size_chars, backend, &out_val) < 0 ) {
310300 return -1 ;
311301 }
312302
@@ -351,6 +341,56 @@ quad_to_unicode_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMet
351341 return NPY_UNSAFE_CASTING;
352342}
353343
344+ // Helper function: Convert quad to string with adaptive notation
345+ static inline PyObject *
346+ quad_to_string_adaptive (Sleef_quad *sleef_val, npy_intp unicode_size_chars)
347+ {
348+ // Try positional format first to see if it would fit
349+ PyObject *positional_str = Dragon4_Positional_QuadDType (
350+ sleef_val, DigitMode_Unique, CutoffMode_TotalLength, SLEEF_QUAD_DECIMAL_DIG, 0 , 1 ,
351+ TrimMode_LeaveOneZero, 1 , 0 );
352+
353+ if (positional_str == NULL ) {
354+ return NULL ;
355+ }
356+
357+ const char *pos_str = PyUnicode_AsUTF8 (positional_str);
358+ if (pos_str == NULL ) {
359+ Py_DECREF (positional_str);
360+ return NULL ;
361+ }
362+
363+ npy_intp pos_len = strlen (pos_str);
364+
365+ // If positional format fits, use it; otherwise use scientific notation
366+ if (pos_len <= unicode_size_chars) {
367+ return positional_str; // Keep the positional string
368+ }
369+ else {
370+ Py_DECREF (positional_str);
371+ // Use scientific notation with full precision
372+ return Dragon4_Scientific_QuadDType (sleef_val, DigitMode_Unique,
373+ SLEEF_QUAD_DECIMAL_DIG, 0 , 1 ,
374+ TrimMode_LeaveOneZero, 1 , 2 );
375+ }
376+ }
377+
378+ // Helper function: Copy string to UCS4 output buffer
379+ static inline void
380+ copy_string_to_ucs4 (const char *str, Py_UCS4 *out_ucs4, npy_intp unicode_size_chars)
381+ {
382+ npy_intp str_len = strlen (str);
383+
384+ for (npy_intp i = 0 ; i < unicode_size_chars; i++) {
385+ if (i < str_len) {
386+ out_ucs4[i] = (Py_UCS4)str[i];
387+ }
388+ else {
389+ out_ucs4[i] = 0 ;
390+ }
391+ }
392+ }
393+
354394static int
355395quad_to_unicode_loop_unaligned (PyArrayMethod_Context *context, char *const data[],
356396 npy_intp const dimensions[], npy_intp const strides[],
@@ -379,46 +419,14 @@ quad_to_unicode_loop_unaligned(PyArrayMethod_Context *context, char *const data[
379419 }
380420
381421 // Convert to Sleef_quad for Dragon4
382- Sleef_quad sleef_val;
383- if (backend == BACKEND_SLEEF) {
384- sleef_val = in_val.sleef_value ;
385- }
386- else {
387- sleef_val = Sleef_cast_from_doubleq1 (in_val.longdouble_value );
388- }
389-
390- // If positional format fits, use it; otherwise use scientific notation
391- PyObject *py_str;
392- PyObject *positional_str = Dragon4_Positional_QuadDType (
393- &sleef_val, DigitMode_Unique, CutoffMode_TotalLength, SLEEF_QUAD_DECIMAL_DIG, 0 , 1 ,
394- TrimMode_LeaveOneZero, 1 , 0 );
395-
396- if (positional_str == NULL ) {
397- return -1 ;
398- }
422+ Sleef_quad sleef_val = quad_to_sleef_quad (&in_val, backend);
399423
400- const char *pos_str = PyUnicode_AsUTF8 (positional_str);
401- if (pos_str == NULL ) {
402- Py_DECREF (positional_str);
424+ // Get string representation with adaptive notation
425+ PyObject *py_str = quad_to_string_adaptive (&sleef_val, unicode_size_chars);
426+ if (py_str == NULL ) {
403427 return -1 ;
404428 }
405429
406- npy_intp pos_len = strlen (pos_str);
407-
408- if (pos_len <= unicode_size_chars) {
409- py_str = positional_str; // Keep the positional string
410- }
411- else {
412- Py_DECREF (positional_str);
413- // Use scientific notation with full precision
414- py_str = Dragon4_Scientific_QuadDType (&sleef_val, DigitMode_Unique,
415- SLEEF_QUAD_DECIMAL_DIG, 0 , 1 ,
416- TrimMode_LeaveOneZero, 1 , 2 );
417- if (py_str == NULL ) {
418- return -1 ;
419- }
420- }
421-
422430 const char *temp_str = PyUnicode_AsUTF8 (py_str);
423431 if (temp_str == NULL ) {
424432 Py_DECREF (py_str);
@@ -427,16 +435,7 @@ quad_to_unicode_loop_unaligned(PyArrayMethod_Context *context, char *const data[
427435
428436 // Convert char string to UCS4 and store in output
429437 Py_UCS4 *out_ucs4 = (Py_UCS4 *)out_ptr;
430- npy_intp str_len = strlen (temp_str);
431-
432- for (npy_intp i = 0 ; i < unicode_size_chars; i++) {
433- if (i < str_len) {
434- out_ucs4[i] = (Py_UCS4)temp_str[i];
435- }
436- else {
437- out_ucs4[i] = 0 ;
438- }
439- }
438+ copy_string_to_ucs4 (temp_str, out_ucs4, unicode_size_chars);
440439
441440 Py_DECREF (py_str);
442441
@@ -474,45 +473,14 @@ quad_to_unicode_loop_aligned(PyArrayMethod_Context *context, char *const data[],
474473 }
475474
476475 // Convert to Sleef_quad for Dragon4
477- Sleef_quad sleef_val;
478- if (backend == BACKEND_SLEEF) {
479- sleef_val = in_val.sleef_value ;
480- }
481- else {
482- sleef_val = Sleef_cast_from_doubleq1 (in_val.longdouble_value );
483- }
476+ Sleef_quad sleef_val = quad_to_sleef_quad (&in_val, backend);
484477
485- PyObject *py_str;
486- PyObject *positional_str = Dragon4_Positional_QuadDType (
487- &sleef_val, DigitMode_Unique, CutoffMode_TotalLength, SLEEF_QUAD_DECIMAL_DIG, 0 , 1 ,
488- TrimMode_LeaveOneZero, 1 , 0 );
489-
490- if (positional_str == NULL ) {
478+ // Get string representation with adaptive notation
479+ PyObject *py_str = quad_to_string_adaptive (&sleef_val, unicode_size_chars);
480+ if (py_str == NULL ) {
491481 return -1 ;
492482 }
493483
494- const char *pos_str = PyUnicode_AsUTF8 (positional_str);
495- if (pos_str == NULL ) {
496- Py_DECREF (positional_str);
497- return -1 ;
498- }
499-
500- npy_intp pos_len = strlen (pos_str);
501-
502- if (pos_len <= unicode_size_chars) {
503- py_str = positional_str;
504- }
505- else {
506- Py_DECREF (positional_str);
507- // Use scientific notation with full precision
508- py_str = Dragon4_Scientific_QuadDType (&sleef_val, DigitMode_Unique,
509- SLEEF_QUAD_DECIMAL_DIG, 0 , 1 ,
510- TrimMode_LeaveOneZero, 1 , 2 );
511- if (py_str == NULL ) {
512- return -1 ;
513- }
514- }
515-
516484 const char *temp_str = PyUnicode_AsUTF8 (py_str);
517485 if (temp_str == NULL ) {
518486 Py_DECREF (py_str);
@@ -521,16 +489,7 @@ quad_to_unicode_loop_aligned(PyArrayMethod_Context *context, char *const data[],
521489
522490 // Convert char string to UCS4 and store in output
523491 Py_UCS4 *out_ucs4 = (Py_UCS4 *)out_ptr;
524- npy_intp str_len = strlen (temp_str);
525-
526- for (npy_intp i = 0 ; i < unicode_size_chars; i++) {
527- if (i < str_len) {
528- out_ucs4[i] = (Py_UCS4)temp_str[i];
529- }
530- else {
531- out_ucs4[i] = 0 ;
532- }
533- }
492+ copy_string_to_ucs4 (temp_str, out_ucs4, unicode_size_chars);
534493
535494 Py_DECREF (py_str);
536495
0 commit comments